From 7bc604ead7164f920bd24b7d6eec4b86ee3d041d Mon Sep 17 00:00:00 2001 From: nikitosing Date: Thu, 27 Jan 2022 15:45:38 +0300 Subject: [PATCH 001/128] Add ability to verify bytecode without bytecode hash --- CHANGELOG.md | 1 + apps/explorer/lib/explorer/smart_contract/solidity/verifier.ex | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8919c1f2552a..98f3d8d96032 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - [#5268](https://github.com/blockscout/blockscout/pull/5268) - Contract names display improvement ### Fixes +- [#5136](https://github.com/blockscout/blockscout/pull/5136) - Improve contract verification - [#5285](https://github.com/blockscout/blockscout/pull/5285) - Fix verified smart-contract bytecode twins feature - [#5269](https://github.com/blockscout/blockscout/pull/5269) - Address Page: Fix implementation address align - [#5264](https://github.com/blockscout/blockscout/pull/5264) - Fix bug with 500 response on `partial` sourcify status diff --git a/apps/explorer/lib/explorer/smart_contract/solidity/verifier.ex b/apps/explorer/lib/explorer/smart_contract/solidity/verifier.ex index 9f4b028ecf82..0a6c8771fe64 100644 --- a/apps/explorer/lib/explorer/smart_contract/solidity/verifier.ex +++ b/apps/explorer/lib/explorer/smart_contract/solidity/verifier.ex @@ -218,6 +218,9 @@ defmodule Explorer.SmartContract.Solidity.Verifier do compiler_version_from_input != generated_compiler_version -> {:error, :compiler_version} + bytecode <> arguments_data == blockchain_created_tx_input -> + {:ok, %{abi: abi, constructor_arguments: arguments_data}} + generated_bytecode != blockchain_bytecode_without_whisper && !try_library_verification(generated_bytecode, blockchain_bytecode_without_whisper) -> {:error, :generated_bytecode} From 7088dca1600ce45910201a7e14181a68176e94b3 Mon Sep 17 00:00:00 2001 From: nikitosing Date: Thu, 27 Jan 2022 16:35:05 +0300 Subject: [PATCH 002/128] Fix vulnerability --- apps/explorer/config/test.exs | 2 +- .../smart_contract/solidity/verifier.ex | 2 +- .../solidity/publisher_test.exs | 25 ++- .../smart_contract/solidity/verifier_test.exs | 170 ++++++++++-------- 4 files changed, 112 insertions(+), 87 deletions(-) diff --git a/apps/explorer/config/test.exs b/apps/explorer/config/test.exs index 1cff6ca47af5..d499642ceb5d 100644 --- a/apps/explorer/config/test.exs +++ b/apps/explorer/config/test.exs @@ -9,7 +9,7 @@ config :explorer, Explorer.Repo, hostname: "localhost", pool: Ecto.Adapters.SQL.Sandbox, # Default of `5_000` was too low for `BlockFetcher` test - ownership_timeout: :timer.minutes(1), + ownership_timeout: :timer.minutes(7), timeout: :timer.seconds(60), queue_target: 1000 diff --git a/apps/explorer/lib/explorer/smart_contract/solidity/verifier.ex b/apps/explorer/lib/explorer/smart_contract/solidity/verifier.ex index 0a6c8771fe64..38c4fcd35c88 100644 --- a/apps/explorer/lib/explorer/smart_contract/solidity/verifier.ex +++ b/apps/explorer/lib/explorer/smart_contract/solidity/verifier.ex @@ -203,7 +203,7 @@ defmodule Explorer.SmartContract.Solidity.Verifier do init_without_0x _ -> - bytecode + "" end %{ diff --git a/apps/explorer/test/explorer/smart_contract/solidity/publisher_test.exs b/apps/explorer/test/explorer/smart_contract/solidity/publisher_test.exs index 35ec6c3ca2e2..7f2bc15e21eb 100644 --- a/apps/explorer/test/explorer/smart_contract/solidity/publisher_test.exs +++ b/apps/explorer/test/explorer/smart_contract/solidity/publisher_test.exs @@ -13,10 +13,13 @@ defmodule Explorer.SmartContract.Solidity.PublisherTest do describe "publish/2" do test "with valid data creates a smart_contract" do - contract_code_info = Factory.contract_code_info() + contract_code_info = Factory.contract_code_info_modern_compilator() contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode) - insert(:transaction, created_contract_address_hash: contract_address.hash, input: contract_code_info.tx_input) + + :transaction + |> insert(created_contract_address_hash: contract_address.hash, input: contract_code_info.tx_input) + |> with_block(status: :ok) valid_attrs = %{ "contract_source_code" => contract_code_info.source_code, @@ -57,7 +60,7 @@ defmodule Explorer.SmartContract.Solidity.PublisherTest do created_contract_address_hash: contract_address.hash, input: input <> expected_constructor_arguments ) - |> with_block() + |> with_block(status: :ok) params = %{ "contract_source_code" => contract, @@ -73,10 +76,13 @@ defmodule Explorer.SmartContract.Solidity.PublisherTest do end test "corresponding contract_methods are created for the abi" do - contract_code_info = Factory.contract_code_info() + contract_code_info = Factory.contract_code_info_modern_compilator() contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode) - insert(:transaction, created_contract_address_hash: contract_address.hash, input: contract_code_info.tx_input) + + :transaction + |> insert(created_contract_address_hash: contract_address.hash, input: contract_code_info.tx_input) + |> with_block(status: :ok) valid_attrs = %{ "contract_source_code" => contract_code_info.source_code, @@ -96,7 +102,7 @@ defmodule Explorer.SmartContract.Solidity.PublisherTest do end test "creates a smart contract with constructor arguments" do - contract_code_info = Factory.contract_code_info() + contract_code_info = Factory.contract_code_info_modern_compilator() contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode) @@ -115,7 +121,7 @@ defmodule Explorer.SmartContract.Solidity.PublisherTest do created_contract_address_hash: contract_address.hash, input: contract_code_info.tx_input <> constructor_arguments ) - |> with_block() + |> with_block(status: :ok) response = Publisher.publish(contract_address.hash, params) assert {:ok, %SmartContract{} = smart_contract} = response @@ -152,7 +158,10 @@ defmodule Explorer.SmartContract.Solidity.PublisherTest do tx_input = contract_data["tx_input"] contract_address = insert(:contract_address, contract_code: "0x" <> expected_bytecode) - insert(:transaction, created_contract_address_hash: contract_address.hash, input: "0x" <> tx_input) + + :transaction + |> insert(created_contract_address_hash: contract_address.hash, input: "0x" <> tx_input) + |> with_block(status: :ok) params = %{ "contract_source_code" => contract, diff --git a/apps/explorer/test/explorer/smart_contract/solidity/verifier_test.exs b/apps/explorer/test/explorer/smart_contract/solidity/verifier_test.exs index 4deee4dc48a0..fd1bda3372ac 100644 --- a/apps/explorer/test/explorer/smart_contract/solidity/verifier_test.exs +++ b/apps/explorer/test/explorer/smart_contract/solidity/verifier_test.exs @@ -69,7 +69,10 @@ defmodule Explorer.SmartContract.Solidity.VerifierTest do contract_code_info: contract_code_info } do contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode) - insert(:transaction, created_contract_address_hash: contract_address.hash, input: contract_code_info.tx_input) + + :transaction + |> insert(created_contract_address_hash: contract_address.hash, input: contract_code_info.tx_input) + |> with_block(status: :ok) params = %{ "contract_source_code" => contract_code_info.source_code, @@ -98,7 +101,10 @@ defmodule Explorer.SmartContract.Solidity.VerifierTest do tx_input = contract_data["tx_input"] contract_address = insert(:contract_address, contract_code: "0x" <> expected_bytecode) - insert(:transaction, created_contract_address_hash: contract_address.hash, input: "0x" <> tx_input) + + :transaction + |> insert(created_contract_address_hash: contract_address.hash, input: "0x" <> tx_input) + |> with_block(status: :ok) params = %{ "contract_source_code" => contract, @@ -133,6 +139,7 @@ defmodule Explorer.SmartContract.Solidity.VerifierTest do created_contract_address_hash: contract_address.hash, input: "0x" <> input ) + |> with_block(status: :ok) params = %{ "contract_source_code" => contract, @@ -166,7 +173,7 @@ defmodule Explorer.SmartContract.Solidity.VerifierTest do created_contract_address_hash: contract_address.hash, input: contract_code_info.tx_input <> constructor_arguments ) - |> with_block() + |> with_block(status: :ok) assert {:ok, %{abi: abi}} = Verifier.evaluate_authenticity(contract_address.hash, params) assert abi != nil @@ -185,7 +192,7 @@ defmodule Explorer.SmartContract.Solidity.VerifierTest do created_contract_address_hash: contract_address.hash, input: bytecode <> constructor_arguments ) - |> with_block() + |> with_block(status: :ok) code = """ pragma solidity ^0.4.15; @@ -222,7 +229,10 @@ defmodule Explorer.SmartContract.Solidity.VerifierTest do "0x610102610026600b82828239805160001a60731461001957fe5b30600052607381538281f3fe730000000000000000000000000000000000000000301460806040526004361060335760003560e01c8063c2985578146038575b600080fd5b603e60b0565b6040805160208082528351818301528351919283929083019185019080838360005b8381101560765781810151838201526020016060565b50505050905090810190601f16801560a25780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b604080518082019091526003815262666f6f60e81b60208201529056fea265627a7a7231582079c18e1f9cf2812147d15e5d44f16ff748f8b7349d32dc9db50300a3ffbd3a9664736f6c634300050b0032" contract_address = insert(:contract_address, contract_code: bytecode) - insert(:transaction, created_contract_address_hash: contract_address.hash, input: bytecode) + + :transaction + |> insert(created_contract_address_hash: contract_address.hash, input: bytecode) + |> with_block(status: :ok) code = """ pragma solidity 0.5.11; @@ -266,7 +276,7 @@ defmodule Explorer.SmartContract.Solidity.VerifierTest do created_contract_address_hash: contract_address.hash, input: input <> constructor_arguments ) - |> with_block() + |> with_block(status: :ok) params = %{ "contract_source_code" => contract, @@ -282,55 +292,58 @@ defmodule Explorer.SmartContract.Solidity.VerifierTest do end # flaky test - # test "returns error when bytecode doesn't match", %{contract_code_info: contract_code_info} do - # contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode) - # insert(:transaction, created_contract_address_hash: contract_address.hash) + test "returns error when bytecode doesn't match", %{contract_code_info: contract_code_info} do + contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode) + + :transaction + |> insert(created_contract_address_hash: contract_address.hash) + |> with_block(status: :ok) - # different_code = "pragma solidity ^0.4.24; contract SimpleStorage {}" + different_code = "pragma solidity ^0.4.24; contract SimpleStorage {}" - # params = %{ - # "contract_source_code" => different_code, - # "compiler_version" => contract_code_info.version, - # "evm_version" => "default", - # "name" => contract_code_info.name, - # "optimization" => contract_code_info.optimized - # } + params = %{ + "contract_source_code" => different_code, + "compiler_version" => contract_code_info.version, + "evm_version" => "default", + "name" => contract_code_info.name, + "optimization" => contract_code_info.optimized + } - # response = Verifier.evaluate_authenticity(contract_address.hash, params) + response = Verifier.evaluate_authenticity(contract_address.hash, params) - # assert {:error, :generated_bytecode} = response - # end + assert {:error, :generated_bytecode} = response + end # flaky test - # test "returns error when contract has constructor arguments and they were not provided" do - # path = File.cwd!() <> "/test/support/fixture/smart_contract/solidity_0.5.9_smart_contract.sol" - # contract = File.read!(path) + test "returns error when contract has constructor arguments and they were not provided" do + path = File.cwd!() <> "/test/support/fixture/smart_contract/solidity_0.5.9_smart_contract.sol" + contract = File.read!(path) - # constructor_arguments = "" + constructor_arguments = "" - # bytecode = - # "0x608060405234801561001057600080fd5b50600436106100a95760003560e01c80633177029f116100715780633177029f1461025f57806354fd4d50146102c557806370a082311461034857806395d89b41146103a0578063a9059cbb14610423578063dd62ed3e14610489576100a9565b806306fdde03146100ae578063095ea7b31461013157806318160ddd1461019757806323b872dd146101b5578063313ce5671461023b575b600080fd5b6100b6610501565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100f65780820151818401526020810190506100db565b50505050905090810190601f1680156101235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61017d6004803603604081101561014757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061059f565b604051808215151515815260200191505060405180910390f35b61019f610691565b6040518082815260200191505060405180910390f35b610221600480360360608110156101cb57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610696565b604051808215151515815260200191505060405180910390f35b61024361090f565b604051808260ff1660ff16815260200191505060405180910390f35b6102ab6004803603604081101561027557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610922565b604051808215151515815260200191505060405180910390f35b6102cd610a14565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561030d5780820151818401526020810190506102f2565b50505050905090810190601f16801561033a5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61038a6004803603602081101561035e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610ab2565b6040518082815260200191505060405180910390f35b6103a8610afa565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103e85780820151818401526020810190506103cd565b50505050905090810190601f1680156104155780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61046f6004803603604081101561043957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610b98565b604051808215151515815260200191505060405180910390f35b6104eb6004803603604081101561049f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610cfe565b6040518082815260200191505060405180910390f35b60038054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156105975780601f1061056c57610100808354040283529160200191610597565b820191906000526020600020905b81548152906001019060200180831161057a57829003601f168201915b505050505081565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b600090565b6000816000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410158015610762575081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410155b801561076e5750600082115b1561090357816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550816000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a360019050610908565b600090505b9392505050565b600460009054906101000a900460ff1681565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b60068054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610aaa5780601f10610a7f57610100808354040283529160200191610aaa565b820191906000526020600020905b815481529060010190602001808311610a8d57829003601f168201915b505050505081565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60058054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610b905780601f10610b6557610100808354040283529160200191610b90565b820191906000526020600020905b815481529060010190602001808311610b7357829003601f168201915b505050505081565b6000816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410158015610be85750600082115b15610cf357816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a360019050610cf8565b600090505b92915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490509291505056fea265627a7a72305820fe0ba5210ac95870683c2cb054304b04565703bd16c7d7e956df694c9643c6d264736f6c63430005090032" + bytecode = + "0x608060405234801561001057600080fd5b50600436106100a95760003560e01c80633177029f116100715780633177029f1461025f57806354fd4d50146102c557806370a082311461034857806395d89b41146103a0578063a9059cbb14610423578063dd62ed3e14610489576100a9565b806306fdde03146100ae578063095ea7b31461013157806318160ddd1461019757806323b872dd146101b5578063313ce5671461023b575b600080fd5b6100b6610501565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100f65780820151818401526020810190506100db565b50505050905090810190601f1680156101235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61017d6004803603604081101561014757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061059f565b604051808215151515815260200191505060405180910390f35b61019f610691565b6040518082815260200191505060405180910390f35b610221600480360360608110156101cb57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610696565b604051808215151515815260200191505060405180910390f35b61024361090f565b604051808260ff1660ff16815260200191505060405180910390f35b6102ab6004803603604081101561027557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610922565b604051808215151515815260200191505060405180910390f35b6102cd610a14565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561030d5780820151818401526020810190506102f2565b50505050905090810190601f16801561033a5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61038a6004803603602081101561035e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610ab2565b6040518082815260200191505060405180910390f35b6103a8610afa565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103e85780820151818401526020810190506103cd565b50505050905090810190601f1680156104155780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61046f6004803603604081101561043957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610b98565b604051808215151515815260200191505060405180910390f35b6104eb6004803603604081101561049f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610cfe565b6040518082815260200191505060405180910390f35b60038054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156105975780601f1061056c57610100808354040283529160200191610597565b820191906000526020600020905b81548152906001019060200180831161057a57829003601f168201915b505050505081565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b600090565b6000816000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410158015610762575081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410155b801561076e5750600082115b1561090357816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550816000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a360019050610908565b600090505b9392505050565b600460009054906101000a900460ff1681565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b60068054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610aaa5780601f10610a7f57610100808354040283529160200191610aaa565b820191906000526020600020905b815481529060010190602001808311610a8d57829003601f168201915b505050505081565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60058054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610b905780601f10610b6557610100808354040283529160200191610b90565b820191906000526020600020905b815481529060010190602001808311610b7357829003601f168201915b505050505081565b6000816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410158015610be85750600082115b15610cf357816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a360019050610cf8565b600090505b92915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490509291505056fea265627a7a72305820fe0ba5210ac95870683c2cb054304b04565703bd16c7d7e956df694c9643c6d264736f6c63430005090032" - # contract_address = insert(:contract_address, contract_code: bytecode) + contract_address = insert(:contract_address, contract_code: bytecode) - # :transaction - # |> insert( - # created_contract_address_hash: contract_address.hash, - # input: bytecode <> constructor_arguments - # ) - # |> with_block() + :transaction + |> insert( + created_contract_address_hash: contract_address.hash, + input: bytecode <> constructor_arguments + ) + |> with_block(status: :ok) - # params = %{ - # "contract_source_code" => contract, - # "compiler_version" => "v0.5.9+commit.e560f70d", - # "evm_version" => "petersburg", - # "name" => "TestToken", - # "optimization" => false, - # "constructor_arguments" => constructor_arguments - # } + params = %{ + "contract_source_code" => contract, + "compiler_version" => "v0.5.9+commit.e560f70d", + "evm_version" => "petersburg", + "name" => "TestToken", + "optimization" => false, + "constructor_arguments" => constructor_arguments + } - # assert {:error, :generated_bytecode} = Verifier.evaluate_authenticity(contract_address.hash, params) - # end + assert {:error, :generated_bytecode} = Verifier.evaluate_authenticity(contract_address.hash, params) + end test "returns error when there is a compilation problem", %{contract_code_info: contract_code_info} do contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode) @@ -395,7 +408,10 @@ defmodule Explorer.SmartContract.Solidity.VerifierTest do "0x60e06040523360601b60c05234801561001757600080fd5b5060405161013f38038061013f8339818101604052604081101561003a57600080fd5b50805160209091015160808290526001600160a01b03163160a081905260c05160601c60cc6100736000395080606652505060cc6000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063fb49908514602d575b600080fd5b605060048036036020811015604157600080fd5b50356001600160a01b03166064565b604080519115158252519081900360200190f35b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b038216311191905056fea2646970667358221220b4fbf35809f2d1b85699a897ebb75d00c8c26b29b72decc53db18ddbd853352164736f6c63430006070033000000000000000000000000000000000000000000000000000000000000000100000000000000000000000023602745048d3b8d0a7f953ad444da4cd237ac83" contract_address = insert(:contract_address, contract_code: bytecode) - insert(:transaction, created_contract_address_hash: contract_address.hash, input: tx_input) + + :transaction + |> insert(created_contract_address_hash: contract_address.hash, input: tx_input) + |> with_block(status: :ok) code = """ pragma solidity >0.6.4 <0.7.0; @@ -559,33 +575,33 @@ defmodule Explorer.SmartContract.Solidity.VerifierTest do describe "compiler version tests" do # flaky test - # test "verification is failed if wrong version of compiler" do - # bytecode_0_5_10 = - # "0x608060405234801561001057600080fd5b506040516102453803806102458339818101604052602081101561003357600080fd5b81019080805190602001909291905050508060008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506101a98061009c6000396000f3fe608060405234801561001057600080fd5b506004361061005e576000357c010000000000000000000000000000000000000000000000000000000090048063256fec88146100635780633fa4f245146100ad578063812600df146100cb575b600080fd5b61006b6100f9565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100b561011f565b6040518082815260200191505060405180910390f35b6100f7600480360360208110156100e157600080fd5b8101908080359060200190929190505050610125565b005b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60005481565b806000540160008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fea265627a7a72305820fb47165501c50aae8ccb0394b15f4302606e0ba55eb6d59fe12eca19ba494d5e64736f6c634300050a0032" - - # constructor_arguments = "000000000000000000000000000000000000000000000000000000000000000a" - # contract_address = insert(:contract_address, contract_code: bytecode_0_5_10) - # bytecode_construtor_arguments = "#{bytecode_0_5_10}#{constructor_arguments}" - - # :transaction - # |> insert( - # created_contract_address_hash: contract_address.hash, - # input: bytecode_construtor_arguments - # ) - # |> with_block() - - # params = %{ - # "contract_source_code" => @code_0_5, - # "compiler_version" => "v0.5.11+commit.c082d0b4", - # "evm_version" => "homestead", - # "name" => "Incrementer", - # "optimization" => false, - # "constructor_arguments" => constructor_arguments - # } - - # response = Verifier.evaluate_authenticity(contract_address.hash, params) - # assert {:error, :compiler_version} = response - # end + test "verification is failed if wrong version of compiler" do + bytecode_0_5_10 = + "0x608060405234801561001057600080fd5b506040516102453803806102458339818101604052602081101561003357600080fd5b81019080805190602001909291905050508060008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506101a98061009c6000396000f3fe608060405234801561001057600080fd5b506004361061005e576000357c010000000000000000000000000000000000000000000000000000000090048063256fec88146100635780633fa4f245146100ad578063812600df146100cb575b600080fd5b61006b6100f9565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100b561011f565b6040518082815260200191505060405180910390f35b6100f7600480360360208110156100e157600080fd5b8101908080359060200190929190505050610125565b005b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60005481565b806000540160008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fea265627a7a72305820fb47165501c50aae8ccb0394b15f4302606e0ba55eb6d59fe12eca19ba494d5e64736f6c634300050a0032" + + constructor_arguments = "000000000000000000000000000000000000000000000000000000000000000a" + contract_address = insert(:contract_address, contract_code: bytecode_0_5_10) + bytecode_construtor_arguments = "#{bytecode_0_5_10}#{constructor_arguments}" + + :transaction + |> insert( + created_contract_address_hash: contract_address.hash, + input: bytecode_construtor_arguments + ) + |> with_block(status: :ok) + + params = %{ + "contract_source_code" => @code_0_5, + "compiler_version" => "v0.5.11+commit.c082d0b4", + "evm_version" => "homestead", + "name" => "Incrementer", + "optimization" => false, + "constructor_arguments" => constructor_arguments + } + + response = Verifier.evaluate_authenticity(contract_address.hash, params) + assert {:error, :compiler_version} = response + end test "verification is successful if proper version of compiler" do bytecode_0_5_10 = @@ -600,7 +616,7 @@ defmodule Explorer.SmartContract.Solidity.VerifierTest do created_contract_address_hash: contract_address.hash, input: bytecode_construtor_arguments ) - |> with_block() + |> with_block(status: :ok) params = %{ "contract_source_code" => @code_0_5, @@ -630,7 +646,7 @@ defmodule Explorer.SmartContract.Solidity.VerifierTest do created_contract_address_hash: contract_address.hash, input: bytecode_construtor_arguments ) - |> with_block() + |> with_block(status: :ok) params = %{ "contract_source_code" => @code_0_4, @@ -658,7 +674,7 @@ defmodule Explorer.SmartContract.Solidity.VerifierTest do created_contract_address_hash: contract_address.hash, input: bytecode_construtor_arguments ) - |> with_block() + |> with_block(status: :ok) params = %{ "contract_source_code" => @code_0_5, @@ -686,7 +702,7 @@ defmodule Explorer.SmartContract.Solidity.VerifierTest do created_contract_address_hash: contract_address.hash, input: bytecode_construtor_arguments ) - |> with_block() + |> with_block(status: :ok) params = %{ "contract_source_code" => @code_0_5, @@ -714,7 +730,7 @@ defmodule Explorer.SmartContract.Solidity.VerifierTest do created_contract_address_hash: contract_address.hash, input: bytecode_construtor_arguments ) - |> with_block() + |> with_block(status: :ok) params = %{ "contract_source_code" => @code_0_5, @@ -742,7 +758,7 @@ defmodule Explorer.SmartContract.Solidity.VerifierTest do created_contract_address_hash: contract_address.hash, input: bytecode_construtor_arguments ) - |> with_block() + |> with_block(status: :ok) params = %{ "contract_source_code" => @code_0_6, From d74c1f223f578988c4914431ab3541ac4d14fdbf Mon Sep 17 00:00:00 2001 From: cen1 Date: Thu, 10 Mar 2022 13:49:25 +0100 Subject: [PATCH 003/128] general video improvements --- .../instance/overview/_details.html.eex | 8 +++--- .../tokens/inventory/_token.html.eex | 2 +- .../views/tokens/instance/overview_view.ex | 25 +++++++++++++++++++ 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/apps/block_scout_web/lib/block_scout_web/templates/tokens/instance/overview/_details.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/tokens/instance/overview/_details.html.eex index c43a52a48601..a8c4fbce51ac 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/tokens/instance/overview/_details.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/tokens/instance/overview/_details.html.eex @@ -61,12 +61,12 @@
- <%= if media_type(media_src(@token_instance.instance)) == "video" do %> -
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/tokens/inventory/_token.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/tokens/inventory/_token.html.eex index 7db024cd0ae5..9fbdca242b11 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/tokens/inventory/_token.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/tokens/inventory/_token.html.eex @@ -46,7 +46,7 @@
<%= if media_type(media_src(@token_transfer.instance)) == "video" do %> -
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex index 5bc87f08879a..bfa3a27d49f6 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex @@ -24,7 +24,7 @@ <%= render BlockScoutWeb.AddressContractVerificationCommonFieldsView, "_include_nightly_builds_field.html", f: f %> - <%= render BlockScoutWeb.AddressContractVerificationCommonFieldsView, "_compiler_field.html", f: f, compiler_version: compiler_version, compiler_versions: @compiler_versions %> + <%= render BlockScoutWeb.AddressContractVerificationCommonFieldsView, "_compiler_field.html", f: f, compiler_version: compiler_version, compiler_versions: @compiler_versions, tooltip: "The compiler version is specified in pragma solidity X.X.X. Use the compiler version rather than the nightly build. If using the Solidity compiler, run solc —version to check." %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_via_standard_json_input/new.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_via_standard_json_input/new.html.eex index 49d1e7089b75..0c1323c2f908 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_via_standard_json_input/new.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_via_standard_json_input/new.html.eex @@ -18,7 +18,7 @@ <%= render BlockScoutWeb.AddressContractVerificationCommonFieldsView, "_include_nightly_builds_field.html", f: f %> - <%= render BlockScoutWeb.AddressContractVerificationCommonFieldsView, "_compiler_field.html", f: f, compiler_version: compiler_version, compiler_versions: @compiler_versions %> + <%= render BlockScoutWeb.AddressContractVerificationCommonFieldsView, "_compiler_field.html", f: f, compiler_version: compiler_version, compiler_versions: @compiler_versions, tooltip: "The compiler version is specified in pragma solidity X.X.X. Use the compiler version rather than the nightly build. If using the Solidity compiler, run solc —version to check." %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_vyper/new.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_vyper/new.html.eex index 327343e0d4a0..33ae40926378 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_vyper/new.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_vyper/new.html.eex @@ -15,9 +15,9 @@ <%= render BlockScoutWeb.AddressContractVerificationCommonFieldsView, "_contract_address_field.html", address_hash: @address_hash, f: f %> - <%= render BlockScoutWeb.AddressContractVerificationCommonFieldsView, "_contract_name_field.html", f: f, tooltip: "Must match the name specified in the code. For example, in contract MyContract {..} MyContract is the contract name.", contract_name_value: contract_name_value %> + <%= render BlockScoutWeb.AddressContractVerificationCommonFieldsView, "_contract_name_field.html", f: f, tooltip: "Must match the name specified in the code.", contract_name_value: contract_name_value %> - <%= render BlockScoutWeb.AddressContractVerificationCommonFieldsView, "_compiler_field.html", f: f, compiler_version: compiler_version, compiler_versions: @compiler_versions %> + <%= render BlockScoutWeb.AddressContractVerificationCommonFieldsView, "_compiler_field.html", f: f, compiler_version: compiler_version, compiler_versions: @compiler_versions, tooltip: "" %>
From 0a60edbe936cec11f17fced57149ddcb57f94098 Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Fri, 25 Mar 2022 09:00:29 +0300 Subject: [PATCH 022/128] Resolve Prototype Pollution in minimist dependency --- CHANGELOG.md | 1 + apps/block_scout_web/assets/package-lock.json | 284 +++++++++--------- apps/explorer/package-lock.json | 2 +- 3 files changed, 144 insertions(+), 143 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 76cc836c20b4..285c216bc961 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ - [#5239](https://github.com/blockscout/blockscout/pull/5239) - Add accounting for block rewards in `getblockreward` api method ### Chore +- [#5367](https://github.com/blockscout/blockscout/pull/5367) - Resolve Prototype Pollution in minimist dependency - [#5366](https://github.com/blockscout/blockscout/pull/5366) - Fix Vyper smart-contract verification form tooltips - [#5341](https://github.com/blockscout/blockscout/pull/5341) - Remove unused broadcasts - [#5318](https://github.com/blockscout/blockscout/pull/5318) - Eliminate Jquery import from chart-loader.js diff --git a/apps/block_scout_web/assets/package-lock.json b/apps/block_scout_web/assets/package-lock.json index 75f3de446b23..8b7b50d44b4a 100644 --- a/apps/block_scout_web/assets/package-lock.json +++ b/apps/block_scout_web/assets/package-lock.json @@ -3303,12 +3303,12 @@ "dev": true }, "node_modules/@walletconnect/browser-utils": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@walletconnect/browser-utils/-/browser-utils-1.7.4.tgz", - "integrity": "sha512-YAM+PyRdJb6WZMUDHPAjlYAad6NrgQypmKiC9iKZhcgcYuFIkbY+tRx+Lp7WAXeZS8TsORagi+Sl4T+MnsRzxA==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@walletconnect/browser-utils/-/browser-utils-1.7.5.tgz", + "integrity": "sha512-gm9ufi0n5cGBXoGWDtMVSqIJ0eXYW+ZFuTNVN0fm4oal26J7cPrOdFjzhv5zvx5fKztWQ21DNFZ+PRXBjXg04Q==", "dependencies": { "@walletconnect/safe-json": "1.0.0", - "@walletconnect/types": "^1.7.4", + "@walletconnect/types": "^1.7.5", "@walletconnect/window-getters": "1.0.0", "@walletconnect/window-metadata": "1.0.0", "detect-browser": "5.2.0" @@ -3320,42 +3320,42 @@ "integrity": "sha512-tr7XntDAu50BVENgQfajMLzacmSe34D+qZc4zjnniz0ZVuw/TZcLcyxHQjYpJTM36sGEkZZlYLnIM1hH7alTMA==" }, "node_modules/@walletconnect/client": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@walletconnect/client/-/client-1.7.4.tgz", - "integrity": "sha512-J6o5vCv84I1ROI7XGHzkabp37TUXpdyqDRQrg6d0usYQVD7B232Hz9jV4K4Ei9PF5CdauXgafFF95Qanlx1shw==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@walletconnect/client/-/client-1.7.5.tgz", + "integrity": "sha512-Vh3h1kfhmJ4Jx//H0lmmfDc5Q2s+R73Nh5cetVN41QPRrAcqHE4lR2ZS8XxRCNBl4/gcHZJIZS9J2Ui4tTXBLA==", "dependencies": { - "@walletconnect/core": "^1.7.4", - "@walletconnect/iso-crypto": "^1.7.4", - "@walletconnect/types": "^1.7.4", - "@walletconnect/utils": "^1.7.4" + "@walletconnect/core": "^1.7.5", + "@walletconnect/iso-crypto": "^1.7.5", + "@walletconnect/types": "^1.7.5", + "@walletconnect/utils": "^1.7.5" } }, "node_modules/@walletconnect/core": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-1.7.4.tgz", - "integrity": "sha512-yhNgyc2r5z4r633J4jMfbcC5PzMq7qlie70rXIOqN2apKnnxffqWEogv9DaZvwV/Lr3h/8aEuGIXP1ModriWPg==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-1.7.5.tgz", + "integrity": "sha512-c4B8s9fZ/Ah2p460Hxo4e9pwLQVYT2+dVYAfqaxVzfYjhAokDEtO55Bdm1hujtRjQVqwTvCljKxBB+LgMp3k8w==", "dependencies": { - "@walletconnect/socket-transport": "^1.7.4", - "@walletconnect/types": "^1.7.4", - "@walletconnect/utils": "^1.7.4" + "@walletconnect/socket-transport": "^1.7.5", + "@walletconnect/types": "^1.7.5", + "@walletconnect/utils": "^1.7.5" } }, "node_modules/@walletconnect/crypto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@walletconnect/crypto/-/crypto-1.0.1.tgz", - "integrity": "sha512-IgUReNrycIFxkGgq8YT9HsosCkhutakWD9Q411PR0aJfxpEa/VKJeaLRtoz6DvJpztWStwhIHnAbBoOVR72a6g==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@walletconnect/crypto/-/crypto-1.0.2.tgz", + "integrity": "sha512-+OlNtwieUqVcOpFTvLBvH+9J9pntEqH5evpINHfVxff1XIgwV55PpbdvkHu6r9Ib4WQDOFiD8OeeXs1vHw7xKQ==", "dependencies": { - "@walletconnect/encoding": "^1.0.0", + "@walletconnect/encoding": "^1.0.1", "@walletconnect/environment": "^1.0.0", - "@walletconnect/randombytes": "^1.0.1", + "@walletconnect/randombytes": "^1.0.2", "aes-js": "^3.1.2", "hash.js": "^1.1.7" } }, "node_modules/@walletconnect/encoding": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@walletconnect/encoding/-/encoding-1.0.0.tgz", - "integrity": "sha512-4nkJFnS0QF5JdieG/3VPD1/iEWkLSZ14EBInLZ00RWxmC6EMZrzAeHNAWIgm+xP3NK0lqz+7lEsmWGtcl5gYnQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@walletconnect/encoding/-/encoding-1.0.1.tgz", + "integrity": "sha512-8opL2rs6N6E3tJfsqwS82aZQDL3gmupWUgmvuZ3CGU7z/InZs3R9jkzH8wmYtpbq0sFK3WkJkQRZFFk4BkrmFA==", "dependencies": { "is-typedarray": "1.0.0", "typedarray-to-buffer": "3.1.5" @@ -3367,12 +3367,12 @@ "integrity": "sha512-4BwqyWy6KpSvkocSaV7WR3BlZfrxLbJSLkg+j7Gl6pTDE+U55lLhJvQaMuDVazXYxcjBsG09k7UlH7cGiUI5vQ==" }, "node_modules/@walletconnect/http-connection": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@walletconnect/http-connection/-/http-connection-1.7.4.tgz", - "integrity": "sha512-vXdAbUZJ9u8fbGvNBqR39p2HLemKqice9S6KDaZWz7EGClN5agoLK+wh3AgZOoZ4gfwhvcqAQvEiEgIXRd2d0w==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@walletconnect/http-connection/-/http-connection-1.7.5.tgz", + "integrity": "sha512-WDy2Y/07c1F107362jel0voeV6QMJuWbwAKNLtxlX8Y9KNzqZAGlHhIZykSWrMjNGwxBaXoqLPmu60uVvodc6A==", "dependencies": { - "@walletconnect/types": "^1.7.4", - "@walletconnect/utils": "^1.7.4", + "@walletconnect/types": "^1.7.5", + "@walletconnect/utils": "^1.7.5", "eventemitter3": "4.0.7", "xhr2-cookies": "1.1.0" } @@ -3383,13 +3383,13 @@ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" }, "node_modules/@walletconnect/iso-crypto": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@walletconnect/iso-crypto/-/iso-crypto-1.7.4.tgz", - "integrity": "sha512-oqLuBcORDO0doaK7LYissviUVlS//jdrhK8GnMMI6mkNh195FHURoi7jUvSE8Nxr5doUNRi9d7bDrEujA++xtw==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@walletconnect/iso-crypto/-/iso-crypto-1.7.5.tgz", + "integrity": "sha512-mJdRs2SqAPOLBBqLhU+ZnAh2c8TL2uDuL/ojV4aBzZ0ZHNT7X2zSOjAiixCb3vvH8GAt30OKmiRo3+ChI/9zvA==", "dependencies": { - "@walletconnect/crypto": "^1.0.1", - "@walletconnect/types": "^1.7.4", - "@walletconnect/utils": "^1.7.4" + "@walletconnect/crypto": "^1.0.2", + "@walletconnect/types": "^1.7.5", + "@walletconnect/utils": "^1.7.5" } }, "node_modules/@walletconnect/jsonrpc-types": { @@ -3416,24 +3416,24 @@ "deprecated": "Deprecated in favor of dynamic registry available from: https://github.com/walletconnect/walletconnect-registry" }, "node_modules/@walletconnect/qrcode-modal": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@walletconnect/qrcode-modal/-/qrcode-modal-1.7.4.tgz", - "integrity": "sha512-e3uHqrscLdFOwF26O0v8nzzyO+8TF5Zb1G+jsn8QB5QLpiDXMMWeQqV0wWM/V80bX/wsvBTL0aSvzeHVvKFWYw==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@walletconnect/qrcode-modal/-/qrcode-modal-1.7.5.tgz", + "integrity": "sha512-LVq35jc3VMGq1EMcGCObQtEiercMDmUHDnc7A3AmUo0LoAbaPo6c8Hq0zqy2+JhtLmxUhU3ktf+szmCoiUDTUQ==", "dependencies": { - "@walletconnect/browser-utils": "^1.7.4", + "@walletconnect/browser-utils": "^1.7.5", "@walletconnect/mobile-registry": "^1.4.0", - "@walletconnect/types": "^1.7.4", + "@walletconnect/types": "^1.7.5", "copy-to-clipboard": "^3.3.1", "preact": "10.4.1", "qrcode": "1.4.4" } }, "node_modules/@walletconnect/randombytes": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@walletconnect/randombytes/-/randombytes-1.0.1.tgz", - "integrity": "sha512-YJTyq69i0PtxVg7osEpKfvjTaWuAsR49QEcqGKZRKVQWMbGXBZ65fovemK/SRgtiFRv0V8PwsrlKSheqzfPNcg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@walletconnect/randombytes/-/randombytes-1.0.2.tgz", + "integrity": "sha512-ivgOtAyqQnN0rLQmOFPemsgYGysd/ooLfaDA/ACQ3cyqlca56t3rZc7pXfqJOIETx/wSyoF5XbwL+BqYodw27A==", "dependencies": { - "@walletconnect/encoding": "^1.0.0", + "@walletconnect/encoding": "^1.0.1", "@walletconnect/environment": "^1.0.0", "randombytes": "^2.1.0" } @@ -3444,12 +3444,12 @@ "integrity": "sha512-QJzp/S/86sUAgWY6eh5MKYmSfZaRpIlmCJdi5uG4DJlKkZrHEF7ye7gA+VtbVzvTtpM/gRwO2plQuiooIeXjfg==" }, "node_modules/@walletconnect/socket-transport": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@walletconnect/socket-transport/-/socket-transport-1.7.4.tgz", - "integrity": "sha512-5RDIZtyQqs5LFqmluE/5Gy4obaClGVDrhlhZJTUn86R49FppJq2pe362NnoJt6J6xLSLZlZ54WIBl6cIlRoVww==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@walletconnect/socket-transport/-/socket-transport-1.7.5.tgz", + "integrity": "sha512-4TYCxrNWb4f5a1NGsALXidr+/6dOiqgVfUQJ4fdP6R7ijL+7jtdiktguU9FIDq5wFXRE+ZdpCpwSAfOt60q/mQ==", "dependencies": { - "@walletconnect/types": "^1.7.4", - "@walletconnect/utils": "^1.7.4", + "@walletconnect/types": "^1.7.5", + "@walletconnect/utils": "^1.7.5", "ws": "7.5.3" } }, @@ -3474,19 +3474,19 @@ } }, "node_modules/@walletconnect/types": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-1.7.4.tgz", - "integrity": "sha512-jvdW1/7z16dCC3i2uwPSgXjUXkmvJH0M2PbYD8ZETyEj/oSiLd32nPAUZVU0IVqQk4XAZHUTKhlRgxTch1W4Qg==" + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-1.7.5.tgz", + "integrity": "sha512-0HvZzxD93et4DdrYgAvclI1BqclkZS7iPWRtbGg3r+PQhRPbOkNypzBy6XH6wflbmr+WBGdmyJvynHsdhcCqUA==" }, "node_modules/@walletconnect/utils": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-1.7.4.tgz", - "integrity": "sha512-09667lbpClPpbskCpLllAQ3MSiNnDlTlqcmWANJ/ZuqCqq5ENyytPqkUjPFSfRfRVkgdQ2t/byeQtDd1TEpHcg==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-1.7.5.tgz", + "integrity": "sha512-U954rIIA/g/Cmdqy+n3hMY1DDMmXxGs8w/QmrK9b/H5nkQ3e4QicOyynq5g/JTTesN5HZdDTFiyX9r0GSKa+iA==", "dependencies": { - "@walletconnect/browser-utils": "^1.7.4", - "@walletconnect/encoding": "^1.0.0", + "@walletconnect/browser-utils": "^1.7.5", + "@walletconnect/encoding": "^1.0.1", "@walletconnect/jsonrpc-utils": "^1.0.0", - "@walletconnect/types": "^1.7.4", + "@walletconnect/types": "^1.7.5", "bn.js": "4.11.8", "js-sha3": "0.8.0", "query-string": "6.13.5" @@ -3522,15 +3522,15 @@ } }, "node_modules/@walletconnect/web3-provider": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@walletconnect/web3-provider/-/web3-provider-1.7.4.tgz", - "integrity": "sha512-VyHyUTx8ovrMRPs0VaMLXUjaG5eNbpK1ZWj+8frOJA18jpgDmtmAVccj0oUukAxuhVTnLZR10KGs0Kd8oWWNTA==", - "dependencies": { - "@walletconnect/client": "^1.7.4", - "@walletconnect/http-connection": "^1.7.4", - "@walletconnect/qrcode-modal": "^1.7.4", - "@walletconnect/types": "^1.7.4", - "@walletconnect/utils": "^1.7.4", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@walletconnect/web3-provider/-/web3-provider-1.7.5.tgz", + "integrity": "sha512-x+UWOTu7jd9qog9NWhaspOmVRDJPnQrgZBscnaSC+x/aAsi52VUrd1GZ9c5UNZFgss41fdx3Z2KhkPeVrlrbuQ==", + "dependencies": { + "@walletconnect/client": "^1.7.5", + "@walletconnect/http-connection": "^1.7.5", + "@walletconnect/qrcode-modal": "^1.7.5", + "@walletconnect/types": "^1.7.5", + "@walletconnect/utils": "^1.7.5", "web3-provider-engine": "16.0.1" } }, @@ -12700,9 +12700,9 @@ } }, "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, "node_modules/minimist-options": { "version": "4.1.0", @@ -20534,12 +20534,12 @@ "dev": true }, "@walletconnect/browser-utils": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@walletconnect/browser-utils/-/browser-utils-1.7.4.tgz", - "integrity": "sha512-YAM+PyRdJb6WZMUDHPAjlYAad6NrgQypmKiC9iKZhcgcYuFIkbY+tRx+Lp7WAXeZS8TsORagi+Sl4T+MnsRzxA==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@walletconnect/browser-utils/-/browser-utils-1.7.5.tgz", + "integrity": "sha512-gm9ufi0n5cGBXoGWDtMVSqIJ0eXYW+ZFuTNVN0fm4oal26J7cPrOdFjzhv5zvx5fKztWQ21DNFZ+PRXBjXg04Q==", "requires": { "@walletconnect/safe-json": "1.0.0", - "@walletconnect/types": "^1.7.4", + "@walletconnect/types": "^1.7.5", "@walletconnect/window-getters": "1.0.0", "@walletconnect/window-metadata": "1.0.0", "detect-browser": "5.2.0" @@ -20553,42 +20553,42 @@ } }, "@walletconnect/client": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@walletconnect/client/-/client-1.7.4.tgz", - "integrity": "sha512-J6o5vCv84I1ROI7XGHzkabp37TUXpdyqDRQrg6d0usYQVD7B232Hz9jV4K4Ei9PF5CdauXgafFF95Qanlx1shw==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@walletconnect/client/-/client-1.7.5.tgz", + "integrity": "sha512-Vh3h1kfhmJ4Jx//H0lmmfDc5Q2s+R73Nh5cetVN41QPRrAcqHE4lR2ZS8XxRCNBl4/gcHZJIZS9J2Ui4tTXBLA==", "requires": { - "@walletconnect/core": "^1.7.4", - "@walletconnect/iso-crypto": "^1.7.4", - "@walletconnect/types": "^1.7.4", - "@walletconnect/utils": "^1.7.4" + "@walletconnect/core": "^1.7.5", + "@walletconnect/iso-crypto": "^1.7.5", + "@walletconnect/types": "^1.7.5", + "@walletconnect/utils": "^1.7.5" } }, "@walletconnect/core": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-1.7.4.tgz", - "integrity": "sha512-yhNgyc2r5z4r633J4jMfbcC5PzMq7qlie70rXIOqN2apKnnxffqWEogv9DaZvwV/Lr3h/8aEuGIXP1ModriWPg==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-1.7.5.tgz", + "integrity": "sha512-c4B8s9fZ/Ah2p460Hxo4e9pwLQVYT2+dVYAfqaxVzfYjhAokDEtO55Bdm1hujtRjQVqwTvCljKxBB+LgMp3k8w==", "requires": { - "@walletconnect/socket-transport": "^1.7.4", - "@walletconnect/types": "^1.7.4", - "@walletconnect/utils": "^1.7.4" + "@walletconnect/socket-transport": "^1.7.5", + "@walletconnect/types": "^1.7.5", + "@walletconnect/utils": "^1.7.5" } }, "@walletconnect/crypto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@walletconnect/crypto/-/crypto-1.0.1.tgz", - "integrity": "sha512-IgUReNrycIFxkGgq8YT9HsosCkhutakWD9Q411PR0aJfxpEa/VKJeaLRtoz6DvJpztWStwhIHnAbBoOVR72a6g==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@walletconnect/crypto/-/crypto-1.0.2.tgz", + "integrity": "sha512-+OlNtwieUqVcOpFTvLBvH+9J9pntEqH5evpINHfVxff1XIgwV55PpbdvkHu6r9Ib4WQDOFiD8OeeXs1vHw7xKQ==", "requires": { - "@walletconnect/encoding": "^1.0.0", + "@walletconnect/encoding": "^1.0.1", "@walletconnect/environment": "^1.0.0", - "@walletconnect/randombytes": "^1.0.1", + "@walletconnect/randombytes": "^1.0.2", "aes-js": "^3.1.2", "hash.js": "^1.1.7" } }, "@walletconnect/encoding": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@walletconnect/encoding/-/encoding-1.0.0.tgz", - "integrity": "sha512-4nkJFnS0QF5JdieG/3VPD1/iEWkLSZ14EBInLZ00RWxmC6EMZrzAeHNAWIgm+xP3NK0lqz+7lEsmWGtcl5gYnQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@walletconnect/encoding/-/encoding-1.0.1.tgz", + "integrity": "sha512-8opL2rs6N6E3tJfsqwS82aZQDL3gmupWUgmvuZ3CGU7z/InZs3R9jkzH8wmYtpbq0sFK3WkJkQRZFFk4BkrmFA==", "requires": { "is-typedarray": "1.0.0", "typedarray-to-buffer": "3.1.5" @@ -20600,12 +20600,12 @@ "integrity": "sha512-4BwqyWy6KpSvkocSaV7WR3BlZfrxLbJSLkg+j7Gl6pTDE+U55lLhJvQaMuDVazXYxcjBsG09k7UlH7cGiUI5vQ==" }, "@walletconnect/http-connection": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@walletconnect/http-connection/-/http-connection-1.7.4.tgz", - "integrity": "sha512-vXdAbUZJ9u8fbGvNBqR39p2HLemKqice9S6KDaZWz7EGClN5agoLK+wh3AgZOoZ4gfwhvcqAQvEiEgIXRd2d0w==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@walletconnect/http-connection/-/http-connection-1.7.5.tgz", + "integrity": "sha512-WDy2Y/07c1F107362jel0voeV6QMJuWbwAKNLtxlX8Y9KNzqZAGlHhIZykSWrMjNGwxBaXoqLPmu60uVvodc6A==", "requires": { - "@walletconnect/types": "^1.7.4", - "@walletconnect/utils": "^1.7.4", + "@walletconnect/types": "^1.7.5", + "@walletconnect/utils": "^1.7.5", "eventemitter3": "4.0.7", "xhr2-cookies": "1.1.0" }, @@ -20618,13 +20618,13 @@ } }, "@walletconnect/iso-crypto": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@walletconnect/iso-crypto/-/iso-crypto-1.7.4.tgz", - "integrity": "sha512-oqLuBcORDO0doaK7LYissviUVlS//jdrhK8GnMMI6mkNh195FHURoi7jUvSE8Nxr5doUNRi9d7bDrEujA++xtw==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@walletconnect/iso-crypto/-/iso-crypto-1.7.5.tgz", + "integrity": "sha512-mJdRs2SqAPOLBBqLhU+ZnAh2c8TL2uDuL/ojV4aBzZ0ZHNT7X2zSOjAiixCb3vvH8GAt30OKmiRo3+ChI/9zvA==", "requires": { - "@walletconnect/crypto": "^1.0.1", - "@walletconnect/types": "^1.7.4", - "@walletconnect/utils": "^1.7.4" + "@walletconnect/crypto": "^1.0.2", + "@walletconnect/types": "^1.7.5", + "@walletconnect/utils": "^1.7.5" } }, "@walletconnect/jsonrpc-types": { @@ -20650,24 +20650,24 @@ "integrity": "sha512-ZtKRio4uCZ1JUF7LIdecmZt7FOLnX72RPSY7aUVu7mj7CSfxDwUn6gBuK6WGtH+NZCldBqDl5DenI5fFSvkKYw==" }, "@walletconnect/qrcode-modal": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@walletconnect/qrcode-modal/-/qrcode-modal-1.7.4.tgz", - "integrity": "sha512-e3uHqrscLdFOwF26O0v8nzzyO+8TF5Zb1G+jsn8QB5QLpiDXMMWeQqV0wWM/V80bX/wsvBTL0aSvzeHVvKFWYw==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@walletconnect/qrcode-modal/-/qrcode-modal-1.7.5.tgz", + "integrity": "sha512-LVq35jc3VMGq1EMcGCObQtEiercMDmUHDnc7A3AmUo0LoAbaPo6c8Hq0zqy2+JhtLmxUhU3ktf+szmCoiUDTUQ==", "requires": { - "@walletconnect/browser-utils": "^1.7.4", + "@walletconnect/browser-utils": "^1.7.5", "@walletconnect/mobile-registry": "^1.4.0", - "@walletconnect/types": "^1.7.4", + "@walletconnect/types": "^1.7.5", "copy-to-clipboard": "^3.3.1", "preact": "10.4.1", "qrcode": "1.4.4" } }, "@walletconnect/randombytes": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@walletconnect/randombytes/-/randombytes-1.0.1.tgz", - "integrity": "sha512-YJTyq69i0PtxVg7osEpKfvjTaWuAsR49QEcqGKZRKVQWMbGXBZ65fovemK/SRgtiFRv0V8PwsrlKSheqzfPNcg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@walletconnect/randombytes/-/randombytes-1.0.2.tgz", + "integrity": "sha512-ivgOtAyqQnN0rLQmOFPemsgYGysd/ooLfaDA/ACQ3cyqlca56t3rZc7pXfqJOIETx/wSyoF5XbwL+BqYodw27A==", "requires": { - "@walletconnect/encoding": "^1.0.0", + "@walletconnect/encoding": "^1.0.1", "@walletconnect/environment": "^1.0.0", "randombytes": "^2.1.0" } @@ -20678,12 +20678,12 @@ "integrity": "sha512-QJzp/S/86sUAgWY6eh5MKYmSfZaRpIlmCJdi5uG4DJlKkZrHEF7ye7gA+VtbVzvTtpM/gRwO2plQuiooIeXjfg==" }, "@walletconnect/socket-transport": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@walletconnect/socket-transport/-/socket-transport-1.7.4.tgz", - "integrity": "sha512-5RDIZtyQqs5LFqmluE/5Gy4obaClGVDrhlhZJTUn86R49FppJq2pe362NnoJt6J6xLSLZlZ54WIBl6cIlRoVww==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@walletconnect/socket-transport/-/socket-transport-1.7.5.tgz", + "integrity": "sha512-4TYCxrNWb4f5a1NGsALXidr+/6dOiqgVfUQJ4fdP6R7ijL+7jtdiktguU9FIDq5wFXRE+ZdpCpwSAfOt60q/mQ==", "requires": { - "@walletconnect/types": "^1.7.4", - "@walletconnect/utils": "^1.7.4", + "@walletconnect/types": "^1.7.5", + "@walletconnect/utils": "^1.7.5", "ws": "7.5.3" }, "dependencies": { @@ -20696,19 +20696,19 @@ } }, "@walletconnect/types": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-1.7.4.tgz", - "integrity": "sha512-jvdW1/7z16dCC3i2uwPSgXjUXkmvJH0M2PbYD8ZETyEj/oSiLd32nPAUZVU0IVqQk4XAZHUTKhlRgxTch1W4Qg==" + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-1.7.5.tgz", + "integrity": "sha512-0HvZzxD93et4DdrYgAvclI1BqclkZS7iPWRtbGg3r+PQhRPbOkNypzBy6XH6wflbmr+WBGdmyJvynHsdhcCqUA==" }, "@walletconnect/utils": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-1.7.4.tgz", - "integrity": "sha512-09667lbpClPpbskCpLllAQ3MSiNnDlTlqcmWANJ/ZuqCqq5ENyytPqkUjPFSfRfRVkgdQ2t/byeQtDd1TEpHcg==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-1.7.5.tgz", + "integrity": "sha512-U954rIIA/g/Cmdqy+n3hMY1DDMmXxGs8w/QmrK9b/H5nkQ3e4QicOyynq5g/JTTesN5HZdDTFiyX9r0GSKa+iA==", "requires": { - "@walletconnect/browser-utils": "^1.7.4", - "@walletconnect/encoding": "^1.0.0", + "@walletconnect/browser-utils": "^1.7.5", + "@walletconnect/encoding": "^1.0.1", "@walletconnect/jsonrpc-utils": "^1.0.0", - "@walletconnect/types": "^1.7.4", + "@walletconnect/types": "^1.7.5", "bn.js": "4.11.8", "js-sha3": "0.8.0", "query-string": "6.13.5" @@ -20737,15 +20737,15 @@ } }, "@walletconnect/web3-provider": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@walletconnect/web3-provider/-/web3-provider-1.7.4.tgz", - "integrity": "sha512-VyHyUTx8ovrMRPs0VaMLXUjaG5eNbpK1ZWj+8frOJA18jpgDmtmAVccj0oUukAxuhVTnLZR10KGs0Kd8oWWNTA==", - "requires": { - "@walletconnect/client": "^1.7.4", - "@walletconnect/http-connection": "^1.7.4", - "@walletconnect/qrcode-modal": "^1.7.4", - "@walletconnect/types": "^1.7.4", - "@walletconnect/utils": "^1.7.4", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@walletconnect/web3-provider/-/web3-provider-1.7.5.tgz", + "integrity": "sha512-x+UWOTu7jd9qog9NWhaspOmVRDJPnQrgZBscnaSC+x/aAsi52VUrd1GZ9c5UNZFgss41fdx3Z2KhkPeVrlrbuQ==", + "requires": { + "@walletconnect/client": "^1.7.5", + "@walletconnect/http-connection": "^1.7.5", + "@walletconnect/qrcode-modal": "^1.7.5", + "@walletconnect/types": "^1.7.5", + "@walletconnect/utils": "^1.7.5", "web3-provider-engine": "16.0.1" } }, @@ -27943,9 +27943,9 @@ } }, "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, "minimist-options": { "version": "4.1.0", diff --git a/apps/explorer/package-lock.json b/apps/explorer/package-lock.json index d2eb2248d781..787f1f877f7f 100644 --- a/apps/explorer/package-lock.json +++ b/apps/explorer/package-lock.json @@ -7,7 +7,7 @@ "name": "blockscout", "license": "GPL-3.0", "dependencies": { - "solc": "0.8.0" + "solc": "^0.8.0" }, "engines": { "node": "16.x", From 6ccdb3c0807d2f41bd2c84d4a1b78a11d5213312 Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Fri, 25 Mar 2022 10:07:14 +0300 Subject: [PATCH 023/128] Refactoring from SourcifyFilePathBackfiller --- CHANGELOG.md | 1 + ...ddress_contract_verification_controller.ex | 94 +------------------ .../api/rpc/contract_controller.ex | 2 +- .../third_party_integrations/sourcify.ex | 92 ++++++++++++++++++ 4 files changed, 95 insertions(+), 94 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 285c216bc961..cf7d59b88b2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ - [#5239](https://github.com/blockscout/blockscout/pull/5239) - Add accounting for block rewards in `getblockreward` api method ### Chore +- [#5368](https://github.com/blockscout/blockscout/pull/5368) - Refactoring from SourcifyFilePathBackfiller - [#5367](https://github.com/blockscout/blockscout/pull/5367) - Resolve Prototype Pollution in minimist dependency - [#5366](https://github.com/blockscout/blockscout/pull/5366) - Fix Vyper smart-contract verification form tooltips - [#5341](https://github.com/blockscout/blockscout/pull/5341) - Remove unused broadcasts diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/address_contract_verification_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/address_contract_verification_controller.ex index d02caf850bee..524a81d33619 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/address_contract_verification_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/address_contract_verification_controller.ex @@ -188,7 +188,7 @@ defmodule BlockScoutWeb.AddressContractVerificationController do "abi" => abi, "secondary_sources" => secondary_sources, "compilation_target_file_path" => compilation_target_file_path - } = parse_params_from_sourcify(address_hash_string, verification_metadata) + } = Sourcify.parse_params_from_sourcify(address_hash_string, verification_metadata) ContractController.publish(conn, %{ "addressHash" => address_hash_string, @@ -225,98 +225,6 @@ defmodule BlockScoutWeb.AddressContractVerificationController do ] end - def parse_params_from_sourcify(address_hash_string, verification_metadata) do - [verification_metadata_json] = - verification_metadata - |> Enum.filter(&(Map.get(&1, "name") == "metadata.json")) - - full_params_initial = parse_json_from_sourcify_for_insertion(verification_metadata_json) - - verification_metadata_sol = - verification_metadata - |> Enum.filter(fn %{"name" => name, "content" => _content} -> name =~ ".sol" end) - - verification_metadata_sol - |> Enum.reduce(full_params_initial, fn %{"name" => name, "content" => content, "path" => _path} = param, - full_params_acc -> - compilation_target_file_name = Map.get(full_params_acc, "compilation_target_file_name") - - if String.downcase(name) == String.downcase(compilation_target_file_name) do - %{ - "params_to_publish" => extract_primary_source_code(content, Map.get(full_params_acc, "params_to_publish")), - "abi" => Map.get(full_params_acc, "abi"), - "secondary_sources" => Map.get(full_params_acc, "secondary_sources"), - "compilation_target_file_path" => Map.get(full_params_acc, "compilation_target_file_path"), - "compilation_target_file_name" => compilation_target_file_name - } - else - secondary_sources = [ - prepare_additional_source(address_hash_string, param) | Map.get(full_params_acc, "secondary_sources") - ] - - %{ - "params_to_publish" => Map.get(full_params_acc, "params_to_publish"), - "abi" => Map.get(full_params_acc, "abi"), - "secondary_sources" => secondary_sources, - "compilation_target_file_path" => Map.get(full_params_acc, "compilation_target_file_path"), - "compilation_target_file_name" => compilation_target_file_name - } - end - end) - end - - defp prepare_additional_source(address_hash_string, %{"name" => _name, "content" => content, "path" => path}) do - splitted_path = - path - |> String.split("/") - - trimmed_path = - splitted_path - |> Enum.slice(9..Enum.count(splitted_path)) - |> Enum.join("/") - - %{ - "address_hash" => address_hash_string, - "file_name" => "/" <> trimmed_path, - "contract_source_code" => content - } - end - - defp extract_primary_source_code(content, params) do - params - |> Map.put("contract_source_code", content) - end - - def parse_json_from_sourcify_for_insertion(verification_metadata_json) do - %{"name" => _, "content" => content} = verification_metadata_json - content_json = Sourcify.decode_json(content) - compiler_version = "v" <> (content_json |> Map.get("compiler") |> Map.get("version")) - abi = content_json |> Map.get("output") |> Map.get("abi") - settings = Map.get(content_json, "settings") - compilation_target_file_path = settings |> Map.get("compilationTarget") |> Map.keys() |> Enum.at(0) - compilation_target_file_name = compilation_target_file_path |> String.split("/") |> Enum.at(-1) - contract_name = settings |> Map.get("compilationTarget") |> Map.get("#{compilation_target_file_path}") - optimizer = Map.get(settings, "optimizer") - - params = - %{} - |> Map.put("name", contract_name) - |> Map.put("compiler_version", compiler_version) - |> Map.put("evm_version", Map.get(settings, "evmVersion")) - |> Map.put("optimization", Map.get(optimizer, "enabled")) - |> Map.put("optimization_runs", Map.get(optimizer, "runs")) - |> Map.put("external_libraries", Map.get(settings, "libraries")) - |> Map.put("verified_via_sourcify", true) - - %{ - "params_to_publish" => params, - "abi" => abi, - "compilation_target_file_path" => compilation_target_file_path, - "compilation_target_file_name" => compilation_target_file_name, - "secondary_sources" => [] - } - end - def parse_optimization_runs(%{"runs" => runs}) do case Integer.parse(runs) do {integer, ""} -> integer diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/contract_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/contract_controller.ex index 8f0c117dc0b1..83676fa5551f 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/contract_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/contract_controller.ex @@ -204,7 +204,7 @@ defmodule BlockScoutWeb.API.RPC.ContractController do case Sourcify.get_metadata(address_hash_string) do {:ok, verification_metadata} -> %{"params_to_publish" => params_to_publish, "abi" => abi, "secondary_sources" => secondary_sources} = - VerificationController.parse_params_from_sourcify(address_hash_string, verification_metadata) + Sourcify.parse_params_from_sourcify(address_hash_string, verification_metadata) case publish_without_broadcast(%{ "addressHash" => address_hash_string, diff --git a/apps/explorer/lib/explorer/third_party_integrations/sourcify.ex b/apps/explorer/lib/explorer/third_party_integrations/sourcify.ex index e2a8d5280c02..2b40e2d70271 100644 --- a/apps/explorer/lib/explorer/third_party_integrations/sourcify.ex +++ b/apps/explorer/lib/explorer/third_party_integrations/sourcify.ex @@ -176,6 +176,98 @@ defmodule Explorer.ThirdPartyIntegrations.Sourcify do end end + def parse_params_from_sourcify(address_hash_string, verification_metadata) do + [verification_metadata_json] = + verification_metadata + |> Enum.filter(&(Map.get(&1, "name") == "metadata.json")) + + full_params_initial = parse_json_from_sourcify_for_insertion(verification_metadata_json) + + verification_metadata_sol = + verification_metadata + |> Enum.filter(fn %{"name" => name, "content" => _content} -> name =~ ".sol" end) + + verification_metadata_sol + |> Enum.reduce(full_params_initial, fn %{"name" => name, "content" => content, "path" => _path} = param, + full_params_acc -> + compilation_target_file_name = Map.get(full_params_acc, "compilation_target_file_name") + + if String.downcase(name) == String.downcase(compilation_target_file_name) do + %{ + "params_to_publish" => extract_primary_source_code(content, Map.get(full_params_acc, "params_to_publish")), + "abi" => Map.get(full_params_acc, "abi"), + "secondary_sources" => Map.get(full_params_acc, "secondary_sources"), + "compilation_target_file_path" => Map.get(full_params_acc, "compilation_target_file_path"), + "compilation_target_file_name" => compilation_target_file_name + } + else + secondary_sources = [ + prepare_additional_source(address_hash_string, param) | Map.get(full_params_acc, "secondary_sources") + ] + + %{ + "params_to_publish" => Map.get(full_params_acc, "params_to_publish"), + "abi" => Map.get(full_params_acc, "abi"), + "secondary_sources" => secondary_sources, + "compilation_target_file_path" => Map.get(full_params_acc, "compilation_target_file_path"), + "compilation_target_file_name" => compilation_target_file_name + } + end + end) + end + + defp parse_json_from_sourcify_for_insertion(verification_metadata_json) do + %{"name" => _, "content" => content} = verification_metadata_json + content_json = decode_json(content) + compiler_version = "v" <> (content_json |> Map.get("compiler") |> Map.get("version")) + abi = content_json |> Map.get("output") |> Map.get("abi") + settings = Map.get(content_json, "settings") + compilation_target_file_path = settings |> Map.get("compilationTarget") |> Map.keys() |> Enum.at(0) + compilation_target_file_name = compilation_target_file_path |> String.split("/") |> Enum.at(-1) + contract_name = settings |> Map.get("compilationTarget") |> Map.get("#{compilation_target_file_path}") + optimizer = Map.get(settings, "optimizer") + + params = + %{} + |> Map.put("name", contract_name) + |> Map.put("compiler_version", compiler_version) + |> Map.put("evm_version", Map.get(settings, "evmVersion")) + |> Map.put("optimization", Map.get(optimizer, "enabled")) + |> Map.put("optimization_runs", Map.get(optimizer, "runs")) + |> Map.put("external_libraries", Map.get(settings, "libraries")) + |> Map.put("verified_via_sourcify", true) + + %{ + "params_to_publish" => params, + "abi" => abi, + "compilation_target_file_path" => compilation_target_file_path, + "compilation_target_file_name" => compilation_target_file_name, + "secondary_sources" => [] + } + end + + defp prepare_additional_source(address_hash_string, %{"name" => _name, "content" => content, "path" => path}) do + splitted_path = + path + |> String.split("/") + + trimmed_path = + splitted_path + |> Enum.slice(9..Enum.count(splitted_path)) + |> Enum.join("/") + + %{ + "address_hash" => address_hash_string, + "file_name" => "/" <> trimmed_path, + "contract_source_code" => content + } + end + + defp extract_primary_source_code(content, params) do + params + |> Map.put("contract_source_code", content) + end + def decode_json(data) do Jason.decode!(data) rescue From ff94813d86b65ff684c5c7c54e2278ae02c3a17b Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Fri, 25 Mar 2022 10:38:02 +0300 Subject: [PATCH 024/128] Minor fix: poison@4.0.1 --- apps/block_scout_web/mix.exs | 2 +- apps/explorer/mix.exs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/block_scout_web/mix.exs b/apps/block_scout_web/mix.exs index 0bc11d48f871..cd470682b908 100644 --- a/apps/block_scout_web/mix.exs +++ b/apps/block_scout_web/mix.exs @@ -104,7 +104,7 @@ defmodule BlockScoutWeb.Mixfile do {:plug_cowboy, "~> 2.2"}, # Waiting for the Pretty Print to be implemented at the Jason lib # https://github.com/michalmuskala/jason/issues/15 - {:poison, "~> 4.0"}, + {:poison, "~> 4.0.1"}, {:postgrex, ">= 0.0.0"}, # For compatibility with `prometheus_process_collector`, which hasn't been updated yet {:prometheus, "~> 4.0", override: true}, diff --git a/apps/explorer/mix.exs b/apps/explorer/mix.exs index 3a5e6bc93cc0..7635bdb09b5e 100644 --- a/apps/explorer/mix.exs +++ b/apps/explorer/mix.exs @@ -86,7 +86,7 @@ defmodule Explorer.Mixfile do {:math, "~> 0.3.0"}, {:mock, "~> 0.3.0", only: [:test], runtime: false}, {:mox, "~> 0.4", only: [:test]}, - {:poison, "~> 4.0"}, + {:poison, "~> 4.0.1"}, {:nimble_csv, "~> 1.1"}, {:postgrex, ">= 0.0.0"}, # For compatibility with `prometheus_process_collector`, which hasn't been updated yet From 302fe49fdee1ad8fb4a285d72767d820101721d1 Mon Sep 17 00:00:00 2001 From: nikitosing Date: Sun, 27 Mar 2022 22:38:11 +0300 Subject: [PATCH 025/128] Fix pending txs fetcher --- CHANGELOG.md | 1 + .../indexer/lib/indexer/fetcher/pending_transaction.ex | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf7d59b88b2e..ba0e31bab2ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - [#5268](https://github.com/blockscout/blockscout/pull/5268) - Contract names display improvement ### Fixes +- [#5375](https://github.com/blockscout/blockscout/pull/5375) - Fix pending transactions fetcher - [#5342](https://github.com/blockscout/blockscout/pull/5342) - Fix 500 error on NF token page with nil metadata - [#5319](https://github.com/blockscout/blockscout/pull/5319), [#5357](https://github.com/blockscout/blockscout/pull/5357) - Empty blocks sanitizer performance improvement - [#5310](https://github.com/blockscout/blockscout/pull/5310) - Fix flash on reload in dark mode diff --git a/apps/indexer/lib/indexer/fetcher/pending_transaction.ex b/apps/indexer/lib/indexer/fetcher/pending_transaction.ex index a5da4b96fb6a..907fd74a5e81 100644 --- a/apps/indexer/lib/indexer/fetcher/pending_transaction.ex +++ b/apps/indexer/lib/indexer/fetcher/pending_transaction.ex @@ -149,6 +149,16 @@ defmodule Indexer.Fetcher.PendingTransaction do {:error, {:bad_gateway, _}} -> Logger.error("bad_gateway") + :ok + + {:error, :closed} -> + Logger.error("closed") + + :ok + + {:error, reason} -> + Logger.error(inspect(reason)) + :ok end end From 8d7d97715158f74654423d4484d57564fee8ddeb Mon Sep 17 00:00:00 2001 From: Ikko Ashimine Date: Mon, 28 Mar 2022 15:30:07 +0900 Subject: [PATCH 026/128] Fix typo in config_helper.ex enviroment -> environment --- apps/explorer/lib/explorer/repo/config_helper.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/explorer/lib/explorer/repo/config_helper.ex b/apps/explorer/lib/explorer/repo/config_helper.ex index 9e0223a1714e..95190555c2b9 100644 --- a/apps/explorer/lib/explorer/repo/config_helper.ex +++ b/apps/explorer/lib/explorer/repo/config_helper.ex @@ -4,7 +4,7 @@ defmodule Explorer.Repo.ConfigHelper do Notably, this module processes the DATABASE_URL environment variable and extracts discrete parameters. - The priority of vars is postgrex enviroment vars < DATABASE_URL components, with values being overwritted by higher priority. + The priority of vars is postgrex environment vars < DATABASE_URL components, with values being overwritted by higher priority. """ # https://hexdocs.pm/postgrex/Postgrex.html#start_link/1-options From 3813bc1f168b9b80ffaed34a22325a3b6e40776d Mon Sep 17 00:00:00 2001 From: nikitosing Date: Tue, 29 Mar 2022 13:47:51 +0300 Subject: [PATCH 027/128] Fix reload transactions button --- CHANGELOG.md | 1 + apps/block_scout_web/assets/js/pages/address/transactions.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba0e31bab2ec..0459fe8d4745 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - [#5268](https://github.com/blockscout/blockscout/pull/5268) - Contract names display improvement ### Fixes +- [#5383](https://github.com/blockscout/blockscout/pull/5383) - Fix reload transactions button - [#5375](https://github.com/blockscout/blockscout/pull/5375) - Fix pending transactions fetcher - [#5342](https://github.com/blockscout/blockscout/pull/5342) - Fix 500 error on NF token page with nil metadata - [#5319](https://github.com/blockscout/blockscout/pull/5319), [#5357](https://github.com/blockscout/blockscout/pull/5357) - Empty blocks sanitizer performance improvement diff --git a/apps/block_scout_web/assets/js/pages/address/transactions.js b/apps/block_scout_web/assets/js/pages/address/transactions.js index 5a31590c1da3..9343d0ca8692 100644 --- a/apps/block_scout_web/assets/js/pages/address/transactions.js +++ b/apps/block_scout_web/assets/js/pages/address/transactions.js @@ -172,7 +172,7 @@ if ($('[data-page="address-transactions"]').length) { } function loadTransactions (store) { - const path = $('[class="card-body"]')[1].dataset.asyncListing + const path = $('[class="card-body"]')[0].dataset.asyncListing store.dispatch({ type: 'START_TRANSACTIONS_FETCH' }) $.getJSON(path, { type: 'JSON' }) .done(response => store.dispatch({ type: 'TRANSACTIONS_FETCHED', msg: humps.camelizeKeys(response) })) From 6ead3869bd800349bafba7e3007d6bd8ee083d38 Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Tue, 29 Mar 2022 17:44:01 +0400 Subject: [PATCH 028/128] Block data for Avalanche: pass blockExtraData and extDataHash params --- CHANGELOG.md | 1 + apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/block.ex | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba0e31bab2ec..966f98f53826 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ - [#5368](https://github.com/blockscout/blockscout/pull/5368) - Refactoring from SourcifyFilePathBackfiller - [#5367](https://github.com/blockscout/blockscout/pull/5367) - Resolve Prototype Pollution in minimist dependency - [#5366](https://github.com/blockscout/blockscout/pull/5366) - Fix Vyper smart-contract verification form tooltips +- [#5348](https://github.com/blockscout/blockscout/pull/5348) - Block data for Avalanche: pass blockExtraData param - [#5341](https://github.com/blockscout/blockscout/pull/5341) - Remove unused broadcasts - [#5318](https://github.com/blockscout/blockscout/pull/5318) - Eliminate Jquery import from chart-loader.js - [#5317](https://github.com/blockscout/blockscout/pull/5317) - NPM audit diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/block.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/block.ex index f8f3fab8b661..f36c5cc742ce 100644 --- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/block.ex +++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/block.ex @@ -588,9 +588,10 @@ defmodule EthereumJSONRPC.Block do # bitcoinMergedMiningCoinbaseTransaction bitcoinMergedMiningHeader bitcoinMergedMiningMerkleProof hashForMergedMining - RSK https://github.com/blockscout/blockscout/pull/2934 # committedSeals committee pastCommittedSeals proposerSeal round - Autonity network https://github.com/blockscout/blockscout/pull/3480 # blockGasCost extDataGasUsed - sgb/ava https://github.com/blockscout/blockscout/pull/5301 + # blockExtraData extDataHash - Avalanche https://github.com/blockscout/blockscout/pull/5348 defp entry_to_elixir({key, _} = entry) when key in ~w(author extraData hash logsBloom miner mixHash nonce parentHash receiptsRoot sealFields sha3Uncles - signature stateRoot step transactionsRoot uncles bitcoinMergedMiningCoinbaseTransaction bitcoinMergedMiningHeader bitcoinMergedMiningMerkleProof hashForMergedMining committedSeals committee pastCommittedSeals proposerSeal round blockGasCost extDataGasUsed), + signature stateRoot step transactionsRoot uncles bitcoinMergedMiningCoinbaseTransaction bitcoinMergedMiningHeader bitcoinMergedMiningMerkleProof hashForMergedMining committedSeals committee pastCommittedSeals proposerSeal round blockGasCost extDataGasUsed blockExtraData extDataHash), do: entry defp entry_to_elixir({"timestamp" = key, timestamp}) do From f9ad92d370ba75d66ffa290eb53a81858c6a960e Mon Sep 17 00:00:00 2001 From: nikitosing Date: Sun, 27 Mar 2022 20:04:53 +0300 Subject: [PATCH 029/128] Return all ERC-1155's token instances in tokenList api endpoint --- CHANGELOG.md | 1 + .../lib/block_scout_web/views/api/rpc/address_view.ex | 1 + apps/explorer/lib/explorer/etherscan.ex | 4 ++-- apps/explorer/test/explorer/etherscan_test.exs | 3 ++- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d6304b172d1..f8a1106b53c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ ### Fixes - [#5383](https://github.com/blockscout/blockscout/pull/5383) - Fix reload transactions button - [#5375](https://github.com/blockscout/blockscout/pull/5375) - Fix pending transactions fetcher +- [#5374](https://github.com/blockscout/blockscout/pull/5374) - Return all ERC-1155's token instances in tokenList api endpoint - [#5342](https://github.com/blockscout/blockscout/pull/5342) - Fix 500 error on NF token page with nil metadata - [#5319](https://github.com/blockscout/blockscout/pull/5319), [#5357](https://github.com/blockscout/blockscout/pull/5357) - Empty blocks sanitizer performance improvement - [#5310](https://github.com/blockscout/blockscout/pull/5310) - Fix flash on reload in dark mode diff --git a/apps/block_scout_web/lib/block_scout_web/views/api/rpc/address_view.ex b/apps/block_scout_web/lib/block_scout_web/views/api/rpc/address_view.ex index 03743acc3225..f7d2f7b02995 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/api/rpc/address_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/api/rpc/address_view.ex @@ -205,6 +205,7 @@ defmodule BlockScoutWeb.API.RPC.AddressView do "symbol" => token.symbol, "type" => token.type } + |> (&if(is_nil(token.id), do: &1, else: Map.put(&1, "id", token.id))).() end defp balance(address) do diff --git a/apps/explorer/lib/explorer/etherscan.ex b/apps/explorer/lib/explorer/etherscan.ex index 406fa4bc3f39..df07914f33ac 100644 --- a/apps/explorer/lib/explorer/etherscan.ex +++ b/apps/explorer/lib/explorer/etherscan.ex @@ -318,14 +318,14 @@ defmodule Explorer.Etherscan do inner_join: t in assoc(ctb, :token), where: ctb.address_hash == ^address_hash, where: ctb.value > 0, - distinct: :token_contract_address_hash, select: %{ balance: ctb.value, contract_address_hash: ctb.token_contract_address_hash, name: t.name, decimals: t.decimals, symbol: t.symbol, - type: t.type + type: t.type, + id: ctb.token_id } ) diff --git a/apps/explorer/test/explorer/etherscan_test.exs b/apps/explorer/test/explorer/etherscan_test.exs index 0e1bf0922aba..2e6490c78b9e 100644 --- a/apps/explorer/test/explorer/etherscan_test.exs +++ b/apps/explorer/test/explorer/etherscan_test.exs @@ -1616,7 +1616,8 @@ defmodule Explorer.EtherscanTest do name: token_balance.token.name, decimals: token_balance.token.decimals, symbol: token_balance.token.symbol, - type: token_balance.token.type + type: token_balance.token.type, + id: token_balance.token_id } ] From 2cfd9d50e17af6d6f4b9a2c0e07fbcf1a06d03e3 Mon Sep 17 00:00:00 2001 From: nikitosing Date: Mon, 28 Mar 2022 23:55:47 +0300 Subject: [PATCH 030/128] Fix Jason encode error --- CHANGELOG.md | 1 + apps/block_scout_web/lib/block_scout_web/notifier.ex | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8a1106b53c0..d9e148ac112f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ ### Fixes - [#5383](https://github.com/blockscout/blockscout/pull/5383) - Fix reload transactions button +- [#5381](https://github.com/blockscout/blockscout/pull/5381) - Fix exchange rate broadcast error - [#5375](https://github.com/blockscout/blockscout/pull/5375) - Fix pending transactions fetcher - [#5374](https://github.com/blockscout/blockscout/pull/5374) - Return all ERC-1155's token instances in tokenList api endpoint - [#5342](https://github.com/blockscout/blockscout/pull/5342) - Fix 500 error on NF token page with nil metadata diff --git a/apps/block_scout_web/lib/block_scout_web/notifier.ex b/apps/block_scout_web/lib/block_scout_web/notifier.ex index f2d85265b32e..b22d34cd29a5 100644 --- a/apps/block_scout_web/lib/block_scout_web/notifier.ex +++ b/apps/block_scout_web/lib/block_scout_web/notifier.ex @@ -105,7 +105,7 @@ defmodule BlockScoutWeb.Notifier do %{exchange_rate | available_supply: nil, market_cap_usd: RSK.market_cap(exchange_rate)} _ -> - exchange_rate + Map.from_struct(exchange_rate) end Endpoint.broadcast("exchange_rate:new_rate", "new_rate", %{ From 07d31179e1cfc0809a8175f25be282fad1304ea6 Mon Sep 17 00:00:00 2001 From: nikitosing Date: Tue, 29 Mar 2022 00:20:51 +0300 Subject: [PATCH 031/128] Fix tests --- .../block_scout_web/channels/exchange_rate_channel_test.exs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/block_scout_web/test/block_scout_web/channels/exchange_rate_channel_test.exs b/apps/block_scout_web/test/block_scout_web/channels/exchange_rate_channel_test.exs index d0ffcc36c875..49c96e2968fb 100644 --- a/apps/block_scout_web/test/block_scout_web/channels/exchange_rate_channel_test.exs +++ b/apps/block_scout_web/test/block_scout_web/channels/exchange_rate_channel_test.exs @@ -20,7 +20,7 @@ defmodule BlockScoutWeb.ExchangeRateChannelTest do ExchangeRates.init([]) - token = %Token{ + token = %{ available_supply: Decimal.new("1000000.0"), total_supply: Decimal.new("1000000.0"), btc_value: Decimal.new("1.000"), @@ -53,7 +53,7 @@ defmodule BlockScoutWeb.ExchangeRateChannelTest do receive do %Phoenix.Socket.Broadcast{topic: ^topic, event: "new_rate", payload: payload} -> - assert payload.exchange_rate == token + assert payload.exchange_rate == Map.from_struct(token) assert payload.market_history_data == [] after :timer.seconds(5) -> From caa84efec18be29d81760bc42d547f1341df3f9a Mon Sep 17 00:00:00 2001 From: nikitosing Date: Thu, 31 Mar 2022 22:37:06 +0300 Subject: [PATCH 032/128] Fix tests --- CHANGELOG.md | 2 +- .../block_scout_web/channels/exchange_rate_channel_test.exs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d9e148ac112f..0ab3642624f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ ### Fixes - [#5383](https://github.com/blockscout/blockscout/pull/5383) - Fix reload transactions button -- [#5381](https://github.com/blockscout/blockscout/pull/5381) - Fix exchange rate broadcast error +- [#5381](https://github.com/blockscout/blockscout/pull/5381), [#5397](https://github.com/blockscout/blockscout/pull/5397) - Fix exchange rate broadcast error - [#5375](https://github.com/blockscout/blockscout/pull/5375) - Fix pending transactions fetcher - [#5374](https://github.com/blockscout/blockscout/pull/5374) - Return all ERC-1155's token instances in tokenList api endpoint - [#5342](https://github.com/blockscout/blockscout/pull/5342) - Fix 500 error on NF token page with nil metadata diff --git a/apps/block_scout_web/test/block_scout_web/channels/exchange_rate_channel_test.exs b/apps/block_scout_web/test/block_scout_web/channels/exchange_rate_channel_test.exs index 49c96e2968fb..bac3c7271832 100644 --- a/apps/block_scout_web/test/block_scout_web/channels/exchange_rate_channel_test.exs +++ b/apps/block_scout_web/test/block_scout_web/channels/exchange_rate_channel_test.exs @@ -20,7 +20,7 @@ defmodule BlockScoutWeb.ExchangeRateChannelTest do ExchangeRates.init([]) - token = %{ + token = %Token{ available_supply: Decimal.new("1000000.0"), total_supply: Decimal.new("1000000.0"), btc_value: Decimal.new("1.000"), @@ -89,7 +89,7 @@ defmodule BlockScoutWeb.ExchangeRateChannelTest do receive do %Phoenix.Socket.Broadcast{topic: ^topic, event: "new_rate", payload: payload} -> - assert payload.exchange_rate == token + assert payload.exchange_rate == Map.from_struct(token) assert payload.market_history_data == records after :timer.seconds(5) -> From bf3a7869e4c112841a2b4524352d7efcaecd195e Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Fri, 25 Mar 2022 11:34:03 +0300 Subject: [PATCH 033/128] Manage indexer memory limit --- .dialyzer-ignore | 2 +- CHANGELOG.md | 1 + apps/block_scout_web/config/config.exs | 6 ++-- apps/block_scout_web/config/dev.exs | 2 +- apps/block_scout_web/config/prod.exs | 2 +- apps/block_scout_web/config/test.exs | 2 +- apps/ethereum_jsonrpc/config/config.exs | 4 +-- apps/ethereum_jsonrpc/config/dev.exs | 2 +- apps/ethereum_jsonrpc/config/prod.exs | 2 +- apps/ethereum_jsonrpc/config/test.exs | 2 +- apps/explorer/config/config.exs | 6 ++-- apps/explorer/config/dev.exs | 2 +- apps/explorer/config/dev/arbitrum.exs | 2 +- apps/explorer/config/dev/besu.exs | 2 +- apps/explorer/config/dev/ganache.exs | 2 +- apps/explorer/config/dev/geth.exs | 2 +- apps/explorer/config/dev/parity.exs | 2 +- apps/explorer/config/dev/rsk.exs | 2 +- apps/explorer/config/prod.exs | 2 +- apps/explorer/config/prod/arbitrum.exs | 2 +- apps/explorer/config/prod/besu.exs | 2 +- apps/explorer/config/prod/ganache.exs | 2 +- apps/explorer/config/prod/geth.exs | 2 +- apps/explorer/config/prod/parity.exs | 2 +- apps/explorer/config/prod/rsk.exs | 2 +- apps/explorer/config/test.exs | 2 +- apps/explorer/config/test/arbitrum.exs | 2 +- apps/explorer/config/test/besu.exs | 2 +- apps/explorer/config/test/ganache.exs | 2 +- apps/explorer/config/test/geth.exs | 2 +- apps/explorer/config/test/parity.exs | 2 +- apps/explorer/config/test/rsk.exs | 2 +- apps/indexer/config/config.exs | 10 ++---- apps/indexer/config/dev.exs | 2 +- apps/indexer/config/dev/arbitrum.exs | 2 +- apps/indexer/config/dev/besu.exs | 2 +- apps/indexer/config/dev/ganache.exs | 2 +- apps/indexer/config/dev/geth.exs | 2 +- apps/indexer/config/dev/parity.exs | 2 +- apps/indexer/config/dev/rsk.exs | 2 +- apps/indexer/config/prod.exs | 2 +- apps/indexer/config/prod/arbitrum.exs | 2 +- apps/indexer/config/prod/besu.exs | 2 +- apps/indexer/config/prod/ganache.exs | 2 +- apps/indexer/config/prod/geth.exs | 2 +- apps/indexer/config/prod/parity.exs | 2 +- apps/indexer/config/prod/rsk.exs | 2 +- apps/indexer/config/test.exs | 2 +- apps/indexer/config/test/arbitrum.exs | 2 +- apps/indexer/config/test/besu.exs | 2 +- apps/indexer/config/test/ganache.exs | 2 +- apps/indexer/config/test/geth.exs | 2 +- apps/indexer/config/test/parity.exs | 2 +- apps/indexer/config/test/rsk.exs | 2 +- .../lib/indexer/empty_blocks_sanitizer.ex | 2 +- apps/indexer/lib/indexer/memory/monitor.ex | 3 +- config/config.exs | 10 +++--- config/dev.exs | 2 +- config/prod.exs | 2 +- config/runtime.exs | 15 ++++++++ config/test.exs | 2 +- docker/Makefile | 3 ++ mix.exs | 34 +++++++++---------- rel/config.exs | 4 ++- 64 files changed, 110 insertions(+), 92 deletions(-) create mode 100644 config/runtime.exs diff --git a/.dialyzer-ignore b/.dialyzer-ignore index d45a57f55c2d..dcd9c797dc04 100644 --- a/.dialyzer-ignore +++ b/.dialyzer-ignore @@ -34,4 +34,4 @@ lib/block_scout_web/views/transaction_view.ex:152 lib/block_scout_web/views/transaction_view.ex:197 lib/indexer/buffered_task.ex:402 lib/indexer/buffered_task.ex:451 -lib/indexer/memory/monitor.ex:161 +lib/indexer/memory/monitor.ex:160 diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ab3642624f7..002afa765c44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ - [#5239](https://github.com/blockscout/blockscout/pull/5239) - Add accounting for block rewards in `getblockreward` api method ### Chore +- [#5369](https://github.com/blockscout/blockscout/pull/5369) - Manage indexer memory limit - [#5368](https://github.com/blockscout/blockscout/pull/5368) - Refactoring from SourcifyFilePathBackfiller - [#5367](https://github.com/blockscout/blockscout/pull/5367) - Resolve Prototype Pollution in minimist dependency - [#5366](https://github.com/blockscout/blockscout/pull/5366) - Fix Vyper smart-contract verification form tooltips diff --git a/apps/block_scout_web/config/config.exs b/apps/block_scout_web/config/config.exs index 51d2db9ba8b2..8392cfdda8a8 100644 --- a/apps/block_scout_web/config/config.exs +++ b/apps/block_scout_web/config/config.exs @@ -1,9 +1,9 @@ # This file is responsible for configuring your application -# and its dependencies with the aid of the Mix.Config module. +# and its dependencies with the aid of the Config module. # # This configuration file is loaded before any dependency and # is restricted to this project. -use Mix.Config +import Config # General application configuration config :block_scout_web, @@ -183,4 +183,4 @@ config :hammer, # Import environment specific config. This must remain at the bottom # of this file so it overrides the configuration defined above. -import_config "#{Mix.env()}.exs" +import_config "#{config_env()}.exs" diff --git a/apps/block_scout_web/config/dev.exs b/apps/block_scout_web/config/dev.exs index 82f9fc6629a7..02b038790cfd 100644 --- a/apps/block_scout_web/config/dev.exs +++ b/apps/block_scout_web/config/dev.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config # For development, we disable any cache and enable # debugging and code reloading. diff --git a/apps/block_scout_web/config/prod.exs b/apps/block_scout_web/config/prod.exs index 2277d38ef08e..fd433c47f110 100644 --- a/apps/block_scout_web/config/prod.exs +++ b/apps/block_scout_web/config/prod.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config # For production, we often load configuration from external # sources, such as your system environment. For this reason, diff --git a/apps/block_scout_web/config/test.exs b/apps/block_scout_web/config/test.exs index 967ee24c708d..a2188c180c7f 100644 --- a/apps/block_scout_web/config/test.exs +++ b/apps/block_scout_web/config/test.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :block_scout_web, :sql_sandbox, true diff --git a/apps/ethereum_jsonrpc/config/config.exs b/apps/ethereum_jsonrpc/config/config.exs index 9a564a1e800f..251b7c7e3a79 100644 --- a/apps/ethereum_jsonrpc/config/config.exs +++ b/apps/ethereum_jsonrpc/config/config.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :ethereum_jsonrpc, EthereumJSONRPC.RequestCoordinator, rolling_window_opts: [ @@ -36,4 +36,4 @@ config :logger, :ethereum_jsonrpc, # Import environment specific config. This must remain at the bottom # of this file so it overrides the configuration defined above. -import_config "#{Mix.env()}.exs" +import_config "#{config_env()}.exs" diff --git a/apps/ethereum_jsonrpc/config/dev.exs b/apps/ethereum_jsonrpc/config/dev.exs index 1f81a56cb5e6..da39fcf0802c 100644 --- a/apps/ethereum_jsonrpc/config/dev.exs +++ b/apps/ethereum_jsonrpc/config/dev.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :ethereum_jsonrpc, EthereumJSONRPC.Tracer, env: "dev", disabled?: true diff --git a/apps/ethereum_jsonrpc/config/prod.exs b/apps/ethereum_jsonrpc/config/prod.exs index 4b4d80babb41..f11e4e7a728c 100644 --- a/apps/ethereum_jsonrpc/config/prod.exs +++ b/apps/ethereum_jsonrpc/config/prod.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :ethereum_jsonrpc, EthereumJSONRPC.Tracer, env: "production", disabled?: true diff --git a/apps/ethereum_jsonrpc/config/test.exs b/apps/ethereum_jsonrpc/config/test.exs index 88e4eba302a9..0ed3de28b282 100644 --- a/apps/ethereum_jsonrpc/config/test.exs +++ b/apps/ethereum_jsonrpc/config/test.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :ethereum_jsonrpc, EthereumJSONRPC.RequestCoordinator, rolling_window_opts: [ diff --git a/apps/explorer/config/config.exs b/apps/explorer/config/config.exs index f83a14c5e7e7..6fe9b7816ecf 100644 --- a/apps/explorer/config/config.exs +++ b/apps/explorer/config/config.exs @@ -1,9 +1,9 @@ # This file is responsible for configuring your application -# and its dependencies with the aid of the Mix.Config module. +# and its dependencies with the aid of the Config module. # # This configuration file is loaded before any dependency and # is restricted to this project. -use Mix.Config +import Config # General application configuration config :explorer, @@ -256,4 +256,4 @@ config :explorer, Explorer.ThirdPartyIntegrations.Sourcify, # Import environment specific config. This must remain at the bottom # of this file so it overrides the configuration defined above. -import_config "#{Mix.env()}.exs" +import_config "#{config_env()}.exs" diff --git a/apps/explorer/config/dev.exs b/apps/explorer/config/dev.exs index c37940c7171e..552e5d29a19d 100644 --- a/apps/explorer/config/dev.exs +++ b/apps/explorer/config/dev.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config database = if System.get_env("DATABASE_URL"), do: nil, else: "explorer_dev" hostname = if System.get_env("DATABASE_URL"), do: nil, else: "localhost" diff --git a/apps/explorer/config/dev/arbitrum.exs b/apps/explorer/config/dev/arbitrum.exs index 1c80b4176564..e3996f056d5e 100644 --- a/apps/explorer/config/dev/arbitrum.exs +++ b/apps/explorer/config/dev/arbitrum.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :explorer, json_rpc_named_arguments: [ diff --git a/apps/explorer/config/dev/besu.exs b/apps/explorer/config/dev/besu.exs index e014ac960cc6..a277e2c68e06 100644 --- a/apps/explorer/config/dev/besu.exs +++ b/apps/explorer/config/dev/besu.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :explorer, json_rpc_named_arguments: [ diff --git a/apps/explorer/config/dev/ganache.exs b/apps/explorer/config/dev/ganache.exs index e6c2214601bd..dcea3bb0490e 100644 --- a/apps/explorer/config/dev/ganache.exs +++ b/apps/explorer/config/dev/ganache.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :explorer, json_rpc_named_arguments: [ diff --git a/apps/explorer/config/dev/geth.exs b/apps/explorer/config/dev/geth.exs index f6a51993c225..f5ba58f1e4f8 100644 --- a/apps/explorer/config/dev/geth.exs +++ b/apps/explorer/config/dev/geth.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :explorer, json_rpc_named_arguments: [ diff --git a/apps/explorer/config/dev/parity.exs b/apps/explorer/config/dev/parity.exs index aebe0dfac123..4008d5eb6d03 100644 --- a/apps/explorer/config/dev/parity.exs +++ b/apps/explorer/config/dev/parity.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :explorer, json_rpc_named_arguments: [ diff --git a/apps/explorer/config/dev/rsk.exs b/apps/explorer/config/dev/rsk.exs index 58af2ee8c0df..2e4a9da4609b 100644 --- a/apps/explorer/config/dev/rsk.exs +++ b/apps/explorer/config/dev/rsk.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :explorer, json_rpc_named_arguments: [ diff --git a/apps/explorer/config/prod.exs b/apps/explorer/config/prod.exs index c12dce364b21..cf1a2d010a6c 100644 --- a/apps/explorer/config/prod.exs +++ b/apps/explorer/config/prod.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config pool_size = if System.get_env("DATABASE_READ_ONLY_API_URL"), diff --git a/apps/explorer/config/prod/arbitrum.exs b/apps/explorer/config/prod/arbitrum.exs index 8ef7b06dbba8..3663189d3da1 100644 --- a/apps/explorer/config/prod/arbitrum.exs +++ b/apps/explorer/config/prod/arbitrum.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :explorer, json_rpc_named_arguments: [ diff --git a/apps/explorer/config/prod/besu.exs b/apps/explorer/config/prod/besu.exs index 4b69e1363ea8..8eaada397108 100644 --- a/apps/explorer/config/prod/besu.exs +++ b/apps/explorer/config/prod/besu.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :explorer, json_rpc_named_arguments: [ diff --git a/apps/explorer/config/prod/ganache.exs b/apps/explorer/config/prod/ganache.exs index c0a4b98a02be..694d1ea4d9e5 100644 --- a/apps/explorer/config/prod/ganache.exs +++ b/apps/explorer/config/prod/ganache.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :explorer, json_rpc_named_arguments: [ diff --git a/apps/explorer/config/prod/geth.exs b/apps/explorer/config/prod/geth.exs index 026d745e9b4a..026c06204749 100644 --- a/apps/explorer/config/prod/geth.exs +++ b/apps/explorer/config/prod/geth.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :explorer, json_rpc_named_arguments: [ diff --git a/apps/explorer/config/prod/parity.exs b/apps/explorer/config/prod/parity.exs index 68c1d14fdff9..796a06643388 100644 --- a/apps/explorer/config/prod/parity.exs +++ b/apps/explorer/config/prod/parity.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :explorer, json_rpc_named_arguments: [ diff --git a/apps/explorer/config/prod/rsk.exs b/apps/explorer/config/prod/rsk.exs index fc62a1c43164..316be82dbfd5 100644 --- a/apps/explorer/config/prod/rsk.exs +++ b/apps/explorer/config/prod/rsk.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :explorer, json_rpc_named_arguments: [ diff --git a/apps/explorer/config/test.exs b/apps/explorer/config/test.exs index d499642ceb5d..becfc8e4903b 100644 --- a/apps/explorer/config/test.exs +++ b/apps/explorer/config/test.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config # Lower hashing rounds for faster tests config :bcrypt_elixir, log_rounds: 4 diff --git a/apps/explorer/config/test/arbitrum.exs b/apps/explorer/config/test/arbitrum.exs index 5a910d54171d..2bb92bef1248 100644 --- a/apps/explorer/config/test/arbitrum.exs +++ b/apps/explorer/config/test/arbitrum.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :explorer, json_rpc_named_arguments: [ diff --git a/apps/explorer/config/test/besu.exs b/apps/explorer/config/test/besu.exs index f5c234c7e159..25b35515b4f3 100644 --- a/apps/explorer/config/test/besu.exs +++ b/apps/explorer/config/test/besu.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :explorer, transport: EthereumJSONRPC.HTTP, diff --git a/apps/explorer/config/test/ganache.exs b/apps/explorer/config/test/ganache.exs index abb61a063248..a73d451d403c 100644 --- a/apps/explorer/config/test/ganache.exs +++ b/apps/explorer/config/test/ganache.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :explorer, json_rpc_named_arguments: [ diff --git a/apps/explorer/config/test/geth.exs b/apps/explorer/config/test/geth.exs index 73869e31a33b..ba6792324806 100644 --- a/apps/explorer/config/test/geth.exs +++ b/apps/explorer/config/test/geth.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :explorer, json_rpc_named_arguments: [ diff --git a/apps/explorer/config/test/parity.exs b/apps/explorer/config/test/parity.exs index 0859de439a60..c0e9464f7e04 100644 --- a/apps/explorer/config/test/parity.exs +++ b/apps/explorer/config/test/parity.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :explorer, transport: EthereumJSONRPC.HTTP, diff --git a/apps/explorer/config/test/rsk.exs b/apps/explorer/config/test/rsk.exs index 861525bb0d67..1799a52dc41c 100644 --- a/apps/explorer/config/test/rsk.exs +++ b/apps/explorer/config/test/rsk.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :explorer, transport: EthereumJSONRPC.HTTP, diff --git a/apps/indexer/config/config.exs b/apps/indexer/config/config.exs index 9b39dd5cc8f6..225fe6978a3d 100644 --- a/apps/indexer/config/config.exs +++ b/apps/indexer/config/config.exs @@ -1,8 +1,6 @@ # This file is responsible for configuring your application -# and its dependencies with the aid of the Mix.Config module. -use Mix.Config - -import Bitwise +# and its dependencies with the aid of the Config module. +import Config block_transformers = %{ "clique" => Indexer.Transform.Blocks.Clique, @@ -33,8 +31,6 @@ config :indexer, ecto_repos: [Explorer.Repo], metadata_updater_seconds_interval: String.to_integer(System.get_env("TOKEN_METADATA_UPDATE_INTERVAL") || "#{2 * 24 * 60 * 60}"), - # bytes - memory_limit: 1 <<< 30, first_block: System.get_env("FIRST_BLOCK") || "", last_block: System.get_env("LAST_BLOCK") || "", trace_first_block: System.get_env("TRACE_FIRST_BLOCK") || "", @@ -96,4 +92,4 @@ config :logger, :indexer, # Import environment specific config. This must remain at the bottom # of this file so it overrides the configuration defined above. -import_config "#{Mix.env()}.exs" +import_config "#{config_env()}.exs" diff --git a/apps/indexer/config/dev.exs b/apps/indexer/config/dev.exs index 02061549a832..7124cbf5217c 100644 --- a/apps/indexer/config/dev.exs +++ b/apps/indexer/config/dev.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :indexer, Indexer.Tracer, env: "dev", disabled?: true diff --git a/apps/indexer/config/dev/arbitrum.exs b/apps/indexer/config/dev/arbitrum.exs index f56213ae012d..e0f8de63e29d 100644 --- a/apps/indexer/config/dev/arbitrum.exs +++ b/apps/indexer/config/dev/arbitrum.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :indexer, block_interval: :timer.seconds(5), diff --git a/apps/indexer/config/dev/besu.exs b/apps/indexer/config/dev/besu.exs index 995adbfb716b..af23f64718c1 100644 --- a/apps/indexer/config/dev/besu.exs +++ b/apps/indexer/config/dev/besu.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :indexer, block_interval: :timer.seconds(5), diff --git a/apps/indexer/config/dev/ganache.exs b/apps/indexer/config/dev/ganache.exs index 229d9d36d903..ee377b5022bc 100644 --- a/apps/indexer/config/dev/ganache.exs +++ b/apps/indexer/config/dev/ganache.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :indexer, block_interval: :timer.seconds(5), diff --git a/apps/indexer/config/dev/geth.exs b/apps/indexer/config/dev/geth.exs index 3082fbebf797..e2f26eca4719 100644 --- a/apps/indexer/config/dev/geth.exs +++ b/apps/indexer/config/dev/geth.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :indexer, block_interval: :timer.seconds(5), diff --git a/apps/indexer/config/dev/parity.exs b/apps/indexer/config/dev/parity.exs index bff27731f0e3..b3e14583d753 100644 --- a/apps/indexer/config/dev/parity.exs +++ b/apps/indexer/config/dev/parity.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :indexer, block_interval: :timer.seconds(5), diff --git a/apps/indexer/config/dev/rsk.exs b/apps/indexer/config/dev/rsk.exs index 28c19e6c7f89..8132cb7cd6a2 100644 --- a/apps/indexer/config/dev/rsk.exs +++ b/apps/indexer/config/dev/rsk.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :indexer, block_interval: :timer.seconds(5), diff --git a/apps/indexer/config/prod.exs b/apps/indexer/config/prod.exs index 76f4bcac52af..0fa704c5a64d 100644 --- a/apps/indexer/config/prod.exs +++ b/apps/indexer/config/prod.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :indexer, Indexer.Tracer, env: "production", disabled?: true diff --git a/apps/indexer/config/prod/arbitrum.exs b/apps/indexer/config/prod/arbitrum.exs index dffc501d3597..b2780524c3ec 100644 --- a/apps/indexer/config/prod/arbitrum.exs +++ b/apps/indexer/config/prod/arbitrum.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :indexer, block_interval: :timer.seconds(5), diff --git a/apps/indexer/config/prod/besu.exs b/apps/indexer/config/prod/besu.exs index c6393935fe12..70360adc1a81 100644 --- a/apps/indexer/config/prod/besu.exs +++ b/apps/indexer/config/prod/besu.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :indexer, block_interval: :timer.seconds(5), diff --git a/apps/indexer/config/prod/ganache.exs b/apps/indexer/config/prod/ganache.exs index 229d9d36d903..ee377b5022bc 100644 --- a/apps/indexer/config/prod/ganache.exs +++ b/apps/indexer/config/prod/ganache.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :indexer, block_interval: :timer.seconds(5), diff --git a/apps/indexer/config/prod/geth.exs b/apps/indexer/config/prod/geth.exs index 85d8563ce989..4de0919c2be4 100644 --- a/apps/indexer/config/prod/geth.exs +++ b/apps/indexer/config/prod/geth.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :indexer, block_interval: :timer.seconds(5), diff --git a/apps/indexer/config/prod/parity.exs b/apps/indexer/config/prod/parity.exs index 8dec2934448c..e9dde3481417 100644 --- a/apps/indexer/config/prod/parity.exs +++ b/apps/indexer/config/prod/parity.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :indexer, block_interval: :timer.seconds(5), diff --git a/apps/indexer/config/prod/rsk.exs b/apps/indexer/config/prod/rsk.exs index 5d52ad470d0d..daa5f224548d 100644 --- a/apps/indexer/config/prod/rsk.exs +++ b/apps/indexer/config/prod/rsk.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :indexer, block_interval: :timer.seconds(5), diff --git a/apps/indexer/config/test.exs b/apps/indexer/config/test.exs index e74b5e1abfe4..c1fb6c0c55b0 100644 --- a/apps/indexer/config/test.exs +++ b/apps/indexer/config/test.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :indexer, Indexer.Tracer, disabled?: false diff --git a/apps/indexer/config/test/arbitrum.exs b/apps/indexer/config/test/arbitrum.exs index e2e51342d122..717b3f730be9 100644 --- a/apps/indexer/config/test/arbitrum.exs +++ b/apps/indexer/config/test/arbitrum.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :indexer, json_rpc_named_arguments: [ diff --git a/apps/indexer/config/test/besu.exs b/apps/indexer/config/test/besu.exs index ceaac3a9b486..2d388f17026e 100644 --- a/apps/indexer/config/test/besu.exs +++ b/apps/indexer/config/test/besu.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :indexer, json_rpc_named_arguments: [ diff --git a/apps/indexer/config/test/ganache.exs b/apps/indexer/config/test/ganache.exs index b42177915202..9fa1d7e19949 100644 --- a/apps/indexer/config/test/ganache.exs +++ b/apps/indexer/config/test/ganache.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :indexer, json_rpc_named_arguments: [ diff --git a/apps/indexer/config/test/geth.exs b/apps/indexer/config/test/geth.exs index 7c4b58b31aa8..c70674d063c2 100644 --- a/apps/indexer/config/test/geth.exs +++ b/apps/indexer/config/test/geth.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :indexer, json_rpc_named_arguments: [ diff --git a/apps/indexer/config/test/parity.exs b/apps/indexer/config/test/parity.exs index af3c396e9a90..217587522a62 100644 --- a/apps/indexer/config/test/parity.exs +++ b/apps/indexer/config/test/parity.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :indexer, json_rpc_named_arguments: [ diff --git a/apps/indexer/config/test/rsk.exs b/apps/indexer/config/test/rsk.exs index 15e2768fc7de..998275b2dfe4 100644 --- a/apps/indexer/config/test/rsk.exs +++ b/apps/indexer/config/test/rsk.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config config :indexer, json_rpc_named_arguments: [ diff --git a/apps/indexer/lib/indexer/empty_blocks_sanitizer.ex b/apps/indexer/lib/indexer/empty_blocks_sanitizer.ex index 2e7ed7ee1f09..8551045e93fb 100644 --- a/apps/indexer/lib/indexer/empty_blocks_sanitizer.ex +++ b/apps/indexer/lib/indexer/empty_blocks_sanitizer.ex @@ -16,7 +16,7 @@ defmodule Indexer.EmptyBlocksSanitizer do alias Explorer.Chain.{Block, Transaction} alias Explorer.Chain.Import.Runner.Blocks - # unprocessed emty blocks to fetch at once + # unprocessed empty blocks to fetch at once @limit 1000 @interval :timer.minutes(1) diff --git a/apps/indexer/lib/indexer/memory/monitor.ex b/apps/indexer/lib/indexer/memory/monitor.ex index 3ee826439b67..a63d039be284 100644 --- a/apps/indexer/lib/indexer/memory/monitor.ex +++ b/apps/indexer/lib/indexer/memory/monitor.ex @@ -10,12 +10,11 @@ defmodule Indexer.Memory.Monitor do require Bitwise require Logger - import Bitwise import Indexer.Logger, only: [process: 1] alias Indexer.Memory.Shrinkable - defstruct limit: 1 <<< 30, + defstruct limit: Application.get_env(:indexer, :memory_limit), timer_interval: :timer.minutes(1), timer_reference: nil, shrinkable_set: MapSet.new() diff --git a/config/config.exs b/config/config.exs index 939702dadeb0..edd96d5c06b8 100644 --- a/config/config.exs +++ b/config/config.exs @@ -1,13 +1,15 @@ # This file is responsible for configuring your application -# and its dependencies with the aid of the Mix.Config module. -use Mix.Config +# and its dependencies with the aid of the Config module. +import Config # By default, the umbrella project as well as each child # application will require this configuration file, ensuring # they all use the same configuration. While one could # configure all applications here, we prefer to delegate # back to each application for organization purposes. -import_config "../apps/*/config/config.exs" +for config <- "../apps/*/config/config.exs" |> Path.expand(__DIR__) |> Path.wildcard() do + import_config config +end config :phoenix, :json_library, Jason @@ -60,4 +62,4 @@ config :logger, :error, # Import environment specific config. This must remain at the bottom # of this file so it overrides the configuration defined above. -import_config "#{Mix.env()}.exs" +import_config "#{config_env()}.exs" diff --git a/config/dev.exs b/config/dev.exs index 7f8759b57697..21e6c9fd40f7 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config # DO NOT make it `:debug` or all Ecto logs will be shown for indexer config :logger, :console, level: :info diff --git a/config/prod.exs b/config/prod.exs index 5503ebbacf83..2175810d041f 100644 --- a/config/prod.exs +++ b/config/prod.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config # Do not print debug messages in production diff --git a/config/runtime.exs b/config/runtime.exs new file mode 100644 index 000000000000..8c662645e644 --- /dev/null +++ b/config/runtime.exs @@ -0,0 +1,15 @@ +import Config + +import Bitwise + +indexer_memory_limit = + "INDEXER_MEMORY_LIMIT" + |> System.get_env("1") + |> Integer.parse() + |> case do + {integer, ""} -> integer + _ -> 1 + end + +config :indexer, + memory_limit: indexer_memory_limit <<< 30 diff --git a/config/test.exs b/config/test.exs index ad8cdb57c4c7..915feb80e81f 100644 --- a/config/test.exs +++ b/config/test.exs @@ -1,4 +1,4 @@ -use Mix.Config +import Config # Print only warnings and errors during test diff --git a/docker/Makefile b/docker/Makefile index c969d511db72..a9439db24bbe 100644 --- a/docker/Makefile +++ b/docker/Makefile @@ -392,6 +392,9 @@ endif ifdef COIN_BALANCE_ON_DEMAND_FETCHER_THRESHOLD_MINUTES BLOCKSCOUT_CONTAINER_PARAMS += -e 'COIN_BALANCE_ON_DEMAND_FETCHER_THRESHOLD_MINUTES=$(COIN_BALANCE_ON_DEMAND_FETCHER_THRESHOLD_MINUTES)' endif +ifdef INDEXER_MEMORY_LIMIT + BLOCKSCOUT_CONTAINER_PARAMS += -e 'INDEXER_MEMORY_LIMIT=$(INDEXER_MEMORY_LIMIT)' +endif HAS_BLOCKSCOUT_IMAGE := $(shell docker images | grep -sw "${BS_CONTAINER_IMAGE} ") build: diff --git a/mix.exs b/mix.exs index 9f256f78dded..bbf55f4c9951 100644 --- a/mix.exs +++ b/mix.exs @@ -6,7 +6,7 @@ defmodule BlockScout.Mixfile do def project do [ app: :block_scout, - aliases: aliases(Mix.env()), + # aliases: aliases(config_env()), version: "4.1.2", apps_path: "apps", deps: deps(), @@ -16,7 +16,7 @@ defmodule BlockScout.Mixfile do credo: :test, dialyzer: :test ], - start_permanent: Mix.env() == :prod, + # start_permanent: config_env() == :prod, releases: [ blockscout: [ applications: [ @@ -42,23 +42,23 @@ defmodule BlockScout.Mixfile do ] end - defp aliases(env) do - [ - # to match behavior of `mix test` in `apps/indexer`, which needs to not start applications for `indexer` to - # prevent its supervision tree from starting, which is undesirable in test - test: "test --no-start" - ] ++ env_aliases(env) - end + # defp aliases(env) do + # [ + # # to match behavior of `mix test` in `apps/indexer`, which needs to not start applications for `indexer` to + # # prevent its supervision tree from starting, which is undesirable in test + # test: "test --no-start" + # ] ++ env_aliases(env) + # end - defp env_aliases(:dev) do - [] - end + # defp env_aliases(:dev) do + # [] + # end - defp env_aliases(_env) do - [ - compile: "compile --warnings-as-errors" - ] - end + # defp env_aliases(_env) do + # [ + # compile: "compile --warnings-as-errors" + # ] + # end # Dependencies can be Hex packages: # diff --git a/rel/config.exs b/rel/config.exs index 8227d3662136..eaaa52e36bac 100644 --- a/rel/config.exs +++ b/rel/config.exs @@ -1,3 +1,5 @@ +import Config + # Import all plugins from `rel/plugins` # They can then be used by adding `plugin MyPlugin` to # either an environment, or release definition, where @@ -33,7 +35,7 @@ use Mix.Releases.Config, # This sets the default release built by `mix release` default_release: :default, # This sets the default environment used by `mix release` - default_environment: Mix.env() + default_environment: config_env() # For a full list of config options for both releases # and environments, visit https://hexdocs.pm/distillery/config/distillery.html From 699b42a1b302740317febfe081d5699e1f47404c Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Fri, 1 Apr 2022 15:10:45 +0400 Subject: [PATCH 034/128] Ability to disable block reward, coin balance, token updater fetchers --- apps/indexer/config/config.exs | 9 ++++++++- apps/indexer/lib/indexer/fetcher/coin_balance.ex | 9 +++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/apps/indexer/config/config.exs b/apps/indexer/config/config.exs index 225fe6978a3d..0a98071f2bfb 100644 --- a/apps/indexer/config/config.exs +++ b/apps/indexer/config/config.exs @@ -69,12 +69,19 @@ config :indexer, Indexer.Fetcher.CoinBalanceOnDemand, threshold: coin_balance_on if System.get_env("POS_STAKING_CONTRACT") do config :indexer, Indexer.Fetcher.BlockReward.Supervisor, disabled?: true else - config :indexer, Indexer.Fetcher.BlockReward.Supervisor, disabled?: false + config :indexer, Indexer.Fetcher.BlockReward.Supervisor, + disabled?: System.get_env("INDEXER_DISABLE_BLOCK_REWARD_FETCHER", "false") == "true" end config :indexer, Indexer.Fetcher.InternalTransaction.Supervisor, disabled?: System.get_env("INDEXER_DISABLE_INTERNAL_TRANSACTIONS_FETCHER", "false") == "true" +config :indexer, Indexer.Fetcher.CoinBalance.Supervisor, + disabled?: System.get_env("INDEXER_DISABLE_ADDRESS_COIN_BALANCE_FETCHER", "false") == "true" + +config :indexer, Indexer.Fetcher.TokenUpdater.Supervisor, + disabled?: System.get_env("INDEXER_DISABLE_CATALOGED_TOKEN_UPDATER_FETCHER", "false") == "true" + config :indexer, Indexer.Supervisor, enabled: System.get_env("DISABLE_INDEXER") != "true" config :indexer, Indexer.Tracer, diff --git a/apps/indexer/lib/indexer/fetcher/coin_balance.ex b/apps/indexer/lib/indexer/fetcher/coin_balance.ex index 02ddbd29176d..94ace2f43141 100644 --- a/apps/indexer/lib/indexer/fetcher/coin_balance.ex +++ b/apps/indexer/lib/indexer/fetcher/coin_balance.ex @@ -16,6 +16,7 @@ defmodule Indexer.Fetcher.CoinBalance do alias Explorer.Chain.{Block, Hash} alias Explorer.Chain.Cache.Accounts alias Indexer.{BufferedTask, Tracer} + alias Indexer.Fetcher.CoinBalance.Supervisor, as: CoinBalanceSupervisor @behaviour BufferedTask @@ -34,9 +35,13 @@ defmodule Indexer.Fetcher.CoinBalance do %{required(:address_hash) => Hash.Address.t(), required(:block_number) => Block.block_number()} ]) :: :ok def async_fetch_balances(balance_fields) when is_list(balance_fields) do - entries = Enum.map(balance_fields, &entry/1) + if CoinBalanceSupervisor.disabled?() do + :ok + else + entries = Enum.map(balance_fields, &entry/1) - BufferedTask.buffer(__MODULE__, entries) + BufferedTask.buffer(__MODULE__, entries) + end end @doc false From 423f201296020ede5317d54cb4ee67038986f460 Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Mon, 4 Apr 2022 15:47:47 +0300 Subject: [PATCH 035/128] Update hackney, certifi, tzdata --- CHANGELOG.md | 1 + apps/ethereum_jsonrpc/mix.exs | 2 +- mix.lock | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 002afa765c44..f2fc55f2107c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ - [#5239](https://github.com/blockscout/blockscout/pull/5239) - Add accounting for block rewards in `getblockreward` api method ### Chore +- [#5407](https://github.com/blockscout/blockscout/pull/5407) - Update hackney, certifi, tzdata - [#5369](https://github.com/blockscout/blockscout/pull/5369) - Manage indexer memory limit - [#5368](https://github.com/blockscout/blockscout/pull/5368) - Refactoring from SourcifyFilePathBackfiller - [#5367](https://github.com/blockscout/blockscout/pull/5367) - Resolve Prototype Pollution in minimist dependency diff --git a/apps/ethereum_jsonrpc/mix.exs b/apps/ethereum_jsonrpc/mix.exs index f1fa391c9eca..9fc5d25f19b5 100644 --- a/apps/ethereum_jsonrpc/mix.exs +++ b/apps/ethereum_jsonrpc/mix.exs @@ -84,7 +84,7 @@ defmodule EthereumJsonrpc.MixProject do {:websocket_client, "~> 1.3"}, {:decimal, "~> 1.9"}, {:decorator, "~> 1.4"}, - {:hackney, "~> 1.17.4"}, + {:hackney, "~> 1.18"}, {:poolboy, "~> 1.5.2"} ] end diff --git a/mix.lock b/mix.lock index 513b986f87f2..3aaac2741aef 100644 --- a/mix.lock +++ b/mix.lock @@ -11,7 +11,7 @@ "briefly": {:git, "https://github.com/CargoSense/briefly.git", "25942fba9cad46aaa870ba248c101ffee321ec9b", []}, "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"}, "bypass": {:hex, :bypass, "1.0.0", "b78b3dcb832a71aca5259c1a704b2e14b55fd4e1327ff942598b4e7d1a7ad83d", [:mix], [{:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: false]}], "hexpm", "5a1dc855dfcc86160458c7a70d25f65d498bd8012bd4c06a8d3baa368dda3c45"}, - "certifi": {:hex, :certifi, "2.6.1", "dbab8e5e155a0763eea978c913ca280a6b544bfa115633fa20249c3d396d9493", [:rebar3], [], "hexpm", "524c97b4991b3849dd5c17a631223896272c6b0af446778ba4675a1dff53bb7e"}, + "certifi": {:hex, :certifi, "2.9.0", "6f2a475689dd47f19fb74334859d460a2dc4e3252a3324bd2111b8f0429e7e21", [:rebar3], [], "hexpm", "266da46bdb06d6c6d35fde799bcb28d36d985d424ad7c08b5bb48f5b5cdd4641"}, "cldr_utils": {:hex, :cldr_utils, "2.14.0", "edcef8dd2654b93d84a90087f3536ffabf9c9d82b34ff82bc9ca54c0668b3a4a", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.5", [hex: :certifi, repo: "hexpm", optional: true]}, {:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "6903356ff6988342a29b90637eece4ca98a4ed2b9759c22233d3474ade57645a"}, "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"}, "comeonin": {:hex, :comeonin, "4.1.2", "3eb5620fd8e35508991664b4c2b04dd41e52f1620b36957be837c1d7784b7592", [:mix], [{:argon2_elixir, "~> 1.2", [hex: :argon2_elixir, repo: "hexpm", optional: true]}, {:bcrypt_elixir, "~> 0.12.1 or ~> 1.0", [hex: :bcrypt_elixir, repo: "hexpm", optional: true]}, {:pbkdf2_elixir, "~> 0.12", [hex: :pbkdf2_elixir, repo: "hexpm", optional: true]}], "hexpm", "d8700a0ca4dbb616c22c9b3f6dd539d88deaafec3efe66869d6370c9a559b3e9"}, @@ -56,7 +56,7 @@ "flow": {:hex, :flow, "0.15.0", "503717c0e367b5713336181d5305106840f64abbad32c75d7af5ef1bb0908e38", [:mix], [{:gen_stage, "~> 0.14.0", [hex: :gen_stage, repo: "hexpm", optional: false]}], "hexpm", "d7ecbd4dd38a188494bc996d5014ef8335f436a0b262140a1f6441ae94714581"}, "gen_stage": {:hex, :gen_stage, "0.14.3", "d0c66f1c87faa301c1a85a809a3ee9097a4264b2edf7644bf5c123237ef732bf", [:mix], [], "hexpm", "8453e2289d94c3199396eb517d65d6715ef26bcae0ee83eb5ff7a84445458d76"}, "gettext": {:hex, :gettext, "0.18.2", "7df3ea191bb56c0309c00a783334b288d08a879f53a7014341284635850a6e55", [:mix], [], "hexpm", "f9f537b13d4fdd30f3039d33cb80144c3aa1f8d9698e47d7bcbcc8df93b1f5c5"}, - "hackney": {:hex, :hackney, "1.17.4", "99da4674592504d3fb0cfef0db84c3ba02b4508bae2dff8c0108baa0d6e0977c", [:rebar3], [{:certifi, "~>2.6.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "de16ff4996556c8548d512f4dbe22dd58a587bf3332e7fd362430a7ef3986b16"}, + "hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~>2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"}, "hammer": {:hex, :hammer, "6.0.0", "72ec6fff10e9d63856968988a22ee04c4d6d5248071ddccfbda50aa6c455c1d7", [:mix], [{:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}], "hexpm", "d8e1ec2e534c4aae508b906759e077c3c1eb3e2b9425235d4b7bbab0b016210a"}, "html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"}, "httpoison": {:hex, :httpoison, "1.8.0", "6b85dea15820b7804ef607ff78406ab449dd78bed923a49c7160e1886e987a3d", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "28089eaa98cf90c66265b6b5ad87c59a3729bea2e74e9d08f9b51eb9729b3c3a"}, @@ -120,7 +120,7 @@ "tesla": {:hex, :tesla, "1.3.3", "26ae98627af5c406584aa6755ab5fc96315d70d69a24dd7f8369cfcb75094a45", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "~> 4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "2648f1c276102f9250299e0b7b57f3071c67827349d9173f34c281756a1b124c"}, "timex": {:hex, :timex, "3.7.1", "1157bd18abf2dcfd61ed666b1f73c356b2e97197deccfecafad188629282fb61", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "cb5d815666e30625d517360523ddd023eb1b4bc27c564e7501c3d050115df523"}, "toml": {:hex, :toml, "0.6.2", "38f445df384a17e5d382befe30e3489112a48d3ba4c459e543f748c2f25dd4d1", [:mix], [], "hexpm", "d013e45126d74c0c26a38d31f5e8e9b83ea19fc752470feb9a86071ca5a672fa"}, - "tzdata": {:hex, :tzdata, "1.1.0", "72f5babaa9390d0f131465c8702fa76da0919e37ba32baa90d93c583301a8359", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "18f453739b48d3dc5bcf0e8906d2dc112bb40baafe2c707596d89f3c8dd14034"}, + "tzdata": {:hex, :tzdata, "1.1.1", "20c8043476dfda8504952d00adac41c6eda23912278add38edc140ae0c5bcc46", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "a69cec8352eafcd2e198dea28a34113b60fdc6cb57eb5ad65c10292a6ba89787"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, "wallaby": {:hex, :wallaby, "0.29.1", "7ad61c98a1425db291a392e45504e897b1271c746b40fe9f19f87a86729d2fac", [:mix], [{:ecto_sql, ">= 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}, {:httpoison, "~> 0.12 or ~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:phoenix_ecto, ">= 3.0.0", [hex: :phoenix_ecto, repo: "hexpm", optional: true]}, {:web_driver_client, "~> 0.2.0", [hex: :web_driver_client, repo: "hexpm", optional: false]}], "hexpm", "21b1360c4b13adbb0a1ff5c1053204cc4489ac81e9579c6c5011a27915cb7415"}, "web_driver_client": {:hex, :web_driver_client, "0.2.0", "63b76cd9eb3b0716ec5467a0f8bead73d3d9612e63f7560d21357f03ad86e31a", [:mix], [{:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:tesla, "~> 1.3", [hex: :tesla, repo: "hexpm", optional: false]}], "hexpm", "83cc6092bc3e74926d1c8455f0ce927d5d1d36707b74d9a65e38c084aab0350f"}, From 3bf8469807bd74072e70db6f24fdf987f33e6e3f Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Mon, 4 Apr 2022 16:30:58 +0300 Subject: [PATCH 036/128] Update websocket_client hex package --- CHANGELOG.md | 1 + apps/block_scout_web/mix.exs | 2 +- mix.lock | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f2fc55f2107c..8688f3d2cca0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ - [#5239](https://github.com/blockscout/blockscout/pull/5239) - Add accounting for block rewards in `getblockreward` api method ### Chore +- [#5408](https://github.com/blockscout/blockscout/pull/5408) - Update websocket_client hex package - [#5407](https://github.com/blockscout/blockscout/pull/5407) - Update hackney, certifi, tzdata - [#5369](https://github.com/blockscout/blockscout/pull/5369) - Manage indexer memory limit - [#5368](https://github.com/blockscout/blockscout/pull/5368) - Refactoring from SourcifyFilePathBackfiller diff --git a/apps/block_scout_web/mix.exs b/apps/block_scout_web/mix.exs index cd470682b908..360e350fee0b 100644 --- a/apps/block_scout_web/mix.exs +++ b/apps/block_scout_web/mix.exs @@ -126,7 +126,7 @@ defmodule BlockScoutWeb.Mixfile do {:timex, "~> 3.7.1"}, {:wallaby, "~> 0.28", only: :test, runtime: false}, # `:cowboy` `~> 2.0` and Phoenix 1.4 compatibility - {:websocket_client, "== 1.3.0"}, + {:websocket_client, "~> 1.4"}, {:wobserver, "~> 0.2.0", github: "poanetwork/wobserver", branch: "support-https"}, {:ex_json_schema, "~> 0.6.2"} ] diff --git a/mix.lock b/mix.lock index 3aaac2741aef..b5b70729b71d 100644 --- a/mix.lock +++ b/mix.lock @@ -124,6 +124,6 @@ "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, "wallaby": {:hex, :wallaby, "0.29.1", "7ad61c98a1425db291a392e45504e897b1271c746b40fe9f19f87a86729d2fac", [:mix], [{:ecto_sql, ">= 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}, {:httpoison, "~> 0.12 or ~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:phoenix_ecto, ">= 3.0.0", [hex: :phoenix_ecto, repo: "hexpm", optional: true]}, {:web_driver_client, "~> 0.2.0", [hex: :web_driver_client, repo: "hexpm", optional: false]}], "hexpm", "21b1360c4b13adbb0a1ff5c1053204cc4489ac81e9579c6c5011a27915cb7415"}, "web_driver_client": {:hex, :web_driver_client, "0.2.0", "63b76cd9eb3b0716ec5467a0f8bead73d3d9612e63f7560d21357f03ad86e31a", [:mix], [{:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:tesla, "~> 1.3", [hex: :tesla, repo: "hexpm", optional: false]}], "hexpm", "83cc6092bc3e74926d1c8455f0ce927d5d1d36707b74d9a65e38c084aab0350f"}, - "websocket_client": {:hex, :websocket_client, "1.3.0", "2275d7daaa1cdacebf2068891c9844b15f4fdc3de3ec2602420c2fb486db59b6", [:rebar3], [], "hexpm", "b864fa076f059b615da4ab99240e515b26132ce4d2d0f9df5d7f22f01fa04b65"}, + "websocket_client": {:hex, :websocket_client, "1.4.2", "f1036e3f9427eecdb66808eee56dbcaeb5a1a352306e6a0d0d23a9487205f4d7", [:rebar3], [], "hexpm", "c005e5f8f2f6a8533c497a509dc52f3e6fb42fa2e0d67bff8ebc8802868d84ed"}, "wobserver": {:git, "https://github.com/poanetwork/wobserver.git", "13bcda30a87f4f0be1878920a79433ad831eefbe", [branch: "support-https"]}, } From 16218c112cc604c18a08844c162a0717e2bbb5a5 Mon Sep 17 00:00:00 2001 From: nikitosing Date: Tue, 5 Apr 2022 13:45:09 +0300 Subject: [PATCH 037/128] Fix getsourcecode for EOA addresses --- CHANGELOG.md | 1 + .../lib/block_scout_web/views/api/rpc/contract_view.ex | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8688f3d2cca0..cf77dd58fd04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - [#5268](https://github.com/blockscout/blockscout/pull/5268) - Contract names display improvement ### Fixes +- [#5416](https://github.com/blockscout/blockscout/pull/5416) - Fix getsourcecode for EOA addresses - [#5383](https://github.com/blockscout/blockscout/pull/5383) - Fix reload transactions button - [#5381](https://github.com/blockscout/blockscout/pull/5381), [#5397](https://github.com/blockscout/blockscout/pull/5397) - Fix exchange rate broadcast error - [#5375](https://github.com/blockscout/blockscout/pull/5375) - Fix pending transactions fetcher diff --git a/apps/block_scout_web/lib/block_scout_web/views/api/rpc/contract_view.ex b/apps/block_scout_web/lib/block_scout_web/views/api/rpc/contract_view.ex index 11c5446e9385..e0e9d43ec012 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/api/rpc/contract_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/api/rpc/contract_view.ex @@ -72,6 +72,10 @@ defmodule BlockScoutWeb.API.RPC.ContractView do |> set_proxy_info(contract) end + defp set_proxy_info(contract_output, contract) when contract == %{} do + contract_output + end + defp set_proxy_info(contract_output, contract) do result = if contract.is_proxy do From 9e6bae8929aef1c5df8147d2b5bab2c691cca192 Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Mon, 4 Apr 2022 18:22:03 +0300 Subject: [PATCH 038/128] Handle exited realtime fetcher --- CHANGELOG.md | 1 + apps/indexer/lib/indexer/block/realtime/fetcher.ex | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf77dd58fd04..02d1deea44f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ ### Fixes - [#5416](https://github.com/blockscout/blockscout/pull/5416) - Fix getsourcecode for EOA addresses +- [#5410](https://github.com/blockscout/blockscout/pull/5410) - Handle exited realtime fetcher - [#5383](https://github.com/blockscout/blockscout/pull/5383) - Fix reload transactions button - [#5381](https://github.com/blockscout/blockscout/pull/5381), [#5397](https://github.com/blockscout/blockscout/pull/5397) - Fix exchange rate broadcast error - [#5375](https://github.com/blockscout/blockscout/pull/5375) - Fix pending transactions fetcher diff --git a/apps/indexer/lib/indexer/block/realtime/fetcher.ex b/apps/indexer/lib/indexer/block/realtime/fetcher.ex index 2b96f6ffe354..4529a7613429 100644 --- a/apps/indexer/lib/indexer/block/realtime/fetcher.ex +++ b/apps/indexer/lib/indexer/block/realtime/fetcher.ex @@ -155,6 +155,14 @@ defmodule Indexer.Block.Realtime.Fetcher do Logger.debug(fn -> ["Could not connect to websocket: #{inspect(reason)}. Continuing with polling."] end) state end + catch + :exit, _reason -> + if Map.get(state, :timer) && state.timer do + Process.cancel_timer(state.timer) + end + + timer = schedule_polling() + %{state | timer: timer} end defp subscribe_to_new_heads(state, _), do: state From b82f9bd76b265fe01b4bdfaa4d8c5df04032a5ba Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Tue, 5 Apr 2022 19:12:44 +0300 Subject: [PATCH 039/128] Fix character_not_in_repertoire error for tx revert reason --- CHANGELOG.md | 1 + apps/explorer/lib/explorer/chain.ex | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02d1deea44f8..1b01729a6f2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ ### Fixes - [#5416](https://github.com/blockscout/blockscout/pull/5416) - Fix getsourcecode for EOA addresses +- [#5411](https://github.com/blockscout/blockscout/pull/5411) - Fix character_not_in_repertoire error for tx revert reason - [#5410](https://github.com/blockscout/blockscout/pull/5410) - Handle exited realtime fetcher - [#5383](https://github.com/blockscout/blockscout/pull/5383) - Fix reload transactions button - [#5381](https://github.com/blockscout/blockscout/pull/5381), [#5397](https://github.com/blockscout/blockscout/pull/5397) - Fix exchange rate broadcast error diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index d2e4489b46ff..dbf91daec56c 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -3738,7 +3738,7 @@ defmodule Explorer.Chain do "" end - formatted_revert_reason = format_revert_reason_message(data) + formatted_revert_reason = data |> format_revert_reason_message() |> (&if(String.valid?(&1), do: &1, else: data)).() if byte_size(formatted_revert_reason) > 0 do transaction From 8657638606d50b88bc72caab3eabc03c3ed10672 Mon Sep 17 00:00:00 2001 From: nikitosing Date: Tue, 5 Apr 2022 21:54:17 +0300 Subject: [PATCH 040/128] Add check if address exists for some api methods --- CHANGELOG.md | 1 + .../controllers/api/rpc/address_controller.ex | 19 ++++++++++++------- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b01729a6f2b..342d35d5b454 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ - [#5239](https://github.com/blockscout/blockscout/pull/5239) - Add accounting for block rewards in `getblockreward` api method ### Chore +- [#5419](https://github.com/blockscout/blockscout/pull/5419) - Add check if address exists for some api methods - [#5408](https://github.com/blockscout/blockscout/pull/5408) - Update websocket_client hex package - [#5407](https://github.com/blockscout/blockscout/pull/5407) - Update hackney, certifi, tzdata - [#5369](https://github.com/blockscout/blockscout/pull/5369) - Manage indexer memory limit diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/address_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/address_controller.ex index 2bab5e5b2f62..54ef51a4e4f7 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/address_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/address_controller.ex @@ -100,6 +100,7 @@ defmodule BlockScoutWeb.API.RPC.AddressController do with {:address_param, {:ok, address_param}} <- fetch_address(params), {:format, {:ok, address_hash}} <- to_address_hash(address_param), + {:address, :ok} <- {:address, Chain.check_address_exists(address_hash)}, {:ok, transactions} <- list_transactions(address_hash, options) do render(conn, :txlist, %{transactions: transactions}) else @@ -113,7 +114,7 @@ defmodule BlockScoutWeb.API.RPC.AddressController do |> put_status(200) |> render(:error, error: "Invalid address format") - {:error, :not_found} -> + {_, :not_found} -> render(conn, :error, error: "No transactions found", data: []) end end @@ -148,13 +149,14 @@ defmodule BlockScoutWeb.API.RPC.AddressController do options = optional_params(params) with {:format, {:ok, address_hash}} <- to_address_hash(address_param), + {:address, :ok} <- {:address, Chain.check_address_exists(address_hash)}, {:ok, internal_transactions} <- list_internal_transactions(address_hash, options) do render(conn, :txlistinternal, %{internal_transactions: internal_transactions}) else {:format, :error} -> render(conn, :error, error: "Invalid address format") - {:error, :not_found} -> + {_, :not_found} -> render(conn, :error, error: "No internal transactions found", data: []) end end @@ -165,6 +167,7 @@ defmodule BlockScoutWeb.API.RPC.AddressController do with {:address_param, {:ok, address_param}} <- fetch_address(params), {:format, {:ok, address_hash}} <- to_address_hash(address_param), {:contract_address, {:ok, contract_address_hash}} <- to_contract_address_hash(params["contractaddress"]), + {:address, :ok} <- {:address, Chain.check_address_exists(address_hash)}, {:ok, token_transfers} <- list_token_transfers(address_hash, contract_address_hash, options) do render(conn, :tokentx, %{token_transfers: token_transfers}) else @@ -177,7 +180,7 @@ defmodule BlockScoutWeb.API.RPC.AddressController do {:contract_address, :error} -> render(conn, :error, error: "Invalid contract address format") - {:error, :not_found} -> + {_, :not_found} -> render(conn, :error, error: "No token transfers found", data: []) end end @@ -202,6 +205,7 @@ defmodule BlockScoutWeb.API.RPC.AddressController do def tokenlist(conn, params) do with {:address_param, {:ok, address_param}} <- fetch_address(params), {:format, {:ok, address_hash}} <- to_address_hash(address_param), + {:address, :ok} <- {:address, Chain.check_address_exists(address_hash)}, {:ok, token_list} <- list_tokens(address_hash) do render(conn, :token_list, %{token_list: token_list}) else @@ -211,7 +215,7 @@ defmodule BlockScoutWeb.API.RPC.AddressController do {:format, :error} -> render(conn, :error, error: "Invalid address format") - {:error, :not_found} -> + {_, :not_found} -> render(conn, :error, error: "No tokens found", data: []) end end @@ -221,6 +225,7 @@ defmodule BlockScoutWeb.API.RPC.AddressController do with {:address_param, {:ok, address_param}} <- fetch_address(params), {:format, {:ok, address_hash}} <- to_address_hash(address_param), + {:address, :ok} <- {:address, Chain.check_address_exists(address_hash)}, {:ok, blocks} <- list_blocks(address_hash, options) do render(conn, :getminedblocks, %{blocks: blocks}) else @@ -230,7 +235,7 @@ defmodule BlockScoutWeb.API.RPC.AddressController do {:format, :error} -> render(conn, :error, error: "Invalid address format") - {:error, :not_found} -> + {_, :not_found} -> render(conn, :error, error: "No blocks found", data: []) end end @@ -495,8 +500,8 @@ defmodule BlockScoutWeb.API.RPC.AddressController do end end - defp list_internal_transactions(transaction_hash, options) do - case Etherscan.list_internal_transactions(transaction_hash, options) do + defp list_internal_transactions(address_hash, options) do + case Etherscan.list_internal_transactions(address_hash, options) do [] -> {:error, :not_found} internal_transactions -> {:ok, internal_transactions} end From 6fad5c2d3275014cfe44ec951fec29fafb30beed Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Thu, 7 Apr 2022 15:34:48 +0300 Subject: [PATCH 041/128] Empty blocks sanitizer improvements --- CHANGELOG.md | 2 +- apps/indexer/config/config.exs | 3 ++ .../{ => fetcher}/empty_blocks_sanitizer.ex | 32 ++++++++++++------- apps/indexer/lib/indexer/supervisor.ex | 4 +-- config/runtime.exs | 12 +++++++ 5 files changed, 38 insertions(+), 15 deletions(-) rename apps/indexer/lib/indexer/{ => fetcher}/empty_blocks_sanitizer.ex (90%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 342d35d5b454..69d81f3296f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ - [#5375](https://github.com/blockscout/blockscout/pull/5375) - Fix pending transactions fetcher - [#5374](https://github.com/blockscout/blockscout/pull/5374) - Return all ERC-1155's token instances in tokenList api endpoint - [#5342](https://github.com/blockscout/blockscout/pull/5342) - Fix 500 error on NF token page with nil metadata -- [#5319](https://github.com/blockscout/blockscout/pull/5319), [#5357](https://github.com/blockscout/blockscout/pull/5357) - Empty blocks sanitizer performance improvement +- [#5319](https://github.com/blockscout/blockscout/pull/5319), [#5357](https://github.com/blockscout/blockscout/pull/5357), [#5425](https://github.com/blockscout/blockscout/pull/5425) - Empty blocks sanitizer performance improvement - [#5310](https://github.com/blockscout/blockscout/pull/5310) - Fix flash on reload in dark mode - [#5306](https://github.com/blockscout/blockscout/pull/5306) - Fix indexer bug - [#5300](https://github.com/blockscout/blockscout/pull/5300), [#5305](https://github.com/blockscout/blockscout/pull/5305) - Token instance page: general video improvements diff --git a/apps/indexer/config/config.exs b/apps/indexer/config/config.exs index 0a98071f2bfb..d543da222589 100644 --- a/apps/indexer/config/config.exs +++ b/apps/indexer/config/config.exs @@ -82,6 +82,9 @@ config :indexer, Indexer.Fetcher.CoinBalance.Supervisor, config :indexer, Indexer.Fetcher.TokenUpdater.Supervisor, disabled?: System.get_env("INDEXER_DISABLE_CATALOGED_TOKEN_UPDATER_FETCHER", "false") == "true" +config :indexer, Indexer.Fetcher.EmptyBlocksSanitizer.Supervisor, + disabled?: System.get_env("INDEXER_DISABLE_EMPTY_BLOCK_SANITIZER", "false") == "true" + config :indexer, Indexer.Supervisor, enabled: System.get_env("DISABLE_INDEXER") != "true" config :indexer, Indexer.Tracer, diff --git a/apps/indexer/lib/indexer/empty_blocks_sanitizer.ex b/apps/indexer/lib/indexer/fetcher/empty_blocks_sanitizer.ex similarity index 90% rename from apps/indexer/lib/indexer/empty_blocks_sanitizer.ex rename to apps/indexer/lib/indexer/fetcher/empty_blocks_sanitizer.ex index 8551045e93fb..d70c5496fffd 100644 --- a/apps/indexer/lib/indexer/empty_blocks_sanitizer.ex +++ b/apps/indexer/lib/indexer/fetcher/empty_blocks_sanitizer.ex @@ -1,10 +1,11 @@ -defmodule Indexer.EmptyBlocksSanitizer do +defmodule Indexer.Fetcher.EmptyBlocksSanitizer do @moduledoc """ Periodically checks empty blocks starting from the head of the chain, detects for which blocks transactions should be refetched and lose consensus for block in order to refetch transactions. """ use GenServer + use Indexer.Fetcher require Logger @@ -16,10 +17,7 @@ defmodule Indexer.EmptyBlocksSanitizer do alias Explorer.Chain.{Block, Transaction} alias Explorer.Chain.Import.Runner.Blocks - # unprocessed empty blocks to fetch at once - @limit 1000 - - @interval :timer.minutes(1) + @interval :timer.seconds(10) defstruct interval: @interval, json_rpc_named_arguments: [] @@ -41,6 +39,7 @@ defmodule Indexer.EmptyBlocksSanitizer do GenServer.start_link(__MODULE__, init_opts, gen_server_opts) end + @impl GenServer def init(opts) when is_list(opts) do state = %__MODULE__{ json_rpc_named_arguments: Keyword.fetch!(opts, :json_rpc_named_arguments), @@ -52,11 +51,12 @@ defmodule Indexer.EmptyBlocksSanitizer do {:ok, state} end + @impl GenServer def handle_info( :sanitize_empty_blocks, %{interval: interval, json_rpc_named_arguments: json_rpc_named_arguments} = state ) do - Logger.info("Start sanitizing of empty blocks. Batch size is #{@limit}", + Logger.info("Start sanitizing of empty blocks. Batch size is #{limit()}", fetcher: :empty_blocks_to_refetch ) @@ -68,7 +68,7 @@ defmodule Indexer.EmptyBlocksSanitizer do end defp sanitize_empty_blocks(json_rpc_named_arguments) do - unprocessed_non_empty_blocks_from_db = unprocessed_non_empty_blocks_query_list(@limit) + unprocessed_non_empty_blocks_from_db = unprocessed_non_empty_blocks_query_list(limit()) uniq_block_hashes = unprocessed_non_empty_blocks_from_db @@ -82,7 +82,7 @@ defmodule Indexer.EmptyBlocksSanitizer do ) end - unprocessed_empty_blocks_from_db = unprocessed_empty_blocks_query_list(@limit) + unprocessed_empty_blocks_from_db = unprocessed_empty_blocks_query_list(limit()) unprocessed_empty_blocks_from_db |> Enum.with_index() @@ -135,8 +135,10 @@ defmodule Indexer.EmptyBlocksSanitizer do from(block in Block, where: is_nil(block.is_empty), where: block.consensus == true, - order_by: [desc: block.number], - limit: ^limit + order_by: [asc: block.hash], + limit: ^limit, + offset: 1000, + lock: "FOR UPDATE" ) end @@ -148,7 +150,8 @@ defmodule Indexer.EmptyBlocksSanitizer do inner_join: transaction in Transaction, on: q.number == transaction.block_number, select: q.hash, - distinct: q.hash + distinct: q.hash, + order_by: [asc: q.hash] ) query @@ -163,10 +166,15 @@ defmodule Indexer.EmptyBlocksSanitizer do left_join: transaction in Transaction, on: q.number == transaction.block_number, where: is_nil(transaction.block_number), - select: {q.number, q.hash} + select: {q.number, q.hash}, + order_by: [asc: q.hash] ) query |> Repo.all(timeout: :infinity) end + + defp limit do + Application.get_env(:indexer, __MODULE__)[:batch_size] + end end diff --git a/apps/indexer/lib/indexer/supervisor.ex b/apps/indexer/lib/indexer/supervisor.ex index 4b1d127b6cd8..b813feed40f0 100644 --- a/apps/indexer/lib/indexer/supervisor.ex +++ b/apps/indexer/lib/indexer/supervisor.ex @@ -10,7 +10,6 @@ defmodule Indexer.Supervisor do alias Indexer.{ Block, CalcLpTokensTotalLiqudity, - EmptyBlocksSanitizer, PendingOpsCleaner, PendingTransactionsSanitizer, SetAmbBridgedMetadataForTokens, @@ -24,6 +23,7 @@ defmodule Indexer.Supervisor do CoinBalance, CoinBalanceOnDemand, ContractCode, + EmptyBlocksSanitizer, InternalTransaction, PendingTransaction, ReplacedTransaction, @@ -127,7 +127,7 @@ defmodule Indexer.Supervisor do # Out-of-band fetchers {CoinBalanceOnDemand.Supervisor, [json_rpc_named_arguments]}, - {EmptyBlocksSanitizer, [[json_rpc_named_arguments: json_rpc_named_arguments]]}, + {EmptyBlocksSanitizer.Supervisor, [[json_rpc_named_arguments: json_rpc_named_arguments]]}, {TokenTotalSupplyOnDemand.Supervisor, [json_rpc_named_arguments]}, {PendingTransactionsSanitizer, [[json_rpc_named_arguments: json_rpc_named_arguments]]}, diff --git a/config/runtime.exs b/config/runtime.exs index 8c662645e644..02d0097b79b0 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -13,3 +13,15 @@ indexer_memory_limit = config :indexer, memory_limit: indexer_memory_limit <<< 30 + +indexer_empty_blocks_sanitizer_batch_size = + if System.get_env("INDEXER_EMPTY_BLOCKS_SANITIZER_BATCH_SIZE") do + case Integer.parse(System.get_env("INDEXER_EMPTY_BLOCKS_SANITIZER_BATCH_SIZE")) do + {integer, ""} -> integer + _ -> 100 + end + else + 100 + end + +config :indexer, Indexer.Fetcher.EmptyBlocksSanitizer, batch_size: indexer_empty_blocks_sanitizer_batch_size From c94eb37be1800f6aac2cbe2297d263c90d29819e Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Mon, 10 Jan 2022 17:17:16 +0300 Subject: [PATCH 042/128] Elixir 1.12 -> 1.13 --- .dialyzer-ignore | 1 + .github/workflows/config.yml | 4 +- .tool-versions | 6 +- CHANGELOG.md | 1 + apps/explorer/lib/explorer/chain.ex | 83 ++++++++++------------ apps/indexer/lib/indexer/buffered_task.ex | 8 +-- apps/indexer/lib/indexer/memory/monitor.ex | 2 +- docker/Dockerfile | 2 +- mix.lock | 2 +- 9 files changed, 51 insertions(+), 58 deletions(-) diff --git a/.dialyzer-ignore b/.dialyzer-ignore index dcd9c797dc04..e3385f7b4ae0 100644 --- a/.dialyzer-ignore +++ b/.dialyzer-ignore @@ -4,6 +4,7 @@ :0: Unknown type 'Elixir.Hash':t/0 :0: Unknown type 'Elixir.Address':t/0 apps/ethereum_jsonrpc/lib/ethereum_jsonrpc.ex:400: Function timestamp_to_datetime/1 has no local return +lib/ethereum_jsonrpc/rolling_window.ex:173 lib/explorer/repo/prometheus_logger.ex:8 lib/explorer/smart_contract/solidity/publisher_worker.ex:1 lib/explorer/smart_contract/vyper/publisher_worker.ex:1 diff --git a/.github/workflows/config.yml b/.github/workflows/config.yml index 2c9198eeabeb..67abe0e88316 100644 --- a/.github/workflows/config.yml +++ b/.github/workflows/config.yml @@ -11,8 +11,8 @@ on: env: MIX_ENV: test - OTP_VERSION: '24.2.2' - ELIXIR_VERSION: '1.12.3' + OTP_VERSION: '24.3.3' + ELIXIR_VERSION: '1.13.4' jobs: build-and-cache: diff --git a/.tool-versions b/.tool-versions index 55b9c6dc683b..5c22166c4061 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,3 +1,3 @@ -elixir 1.12.3-otp-24 -erlang 24.2 -nodejs 16.13.0 +elixir 1.13.4-otp-24 +erlang 24.3.3 +nodejs 16.14.2 diff --git a/CHANGELOG.md b/CHANGELOG.md index 69d81f3296f8..558f12e28375 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,7 @@ - [#5287](https://github.com/blockscout/blockscout/pull/5287) - Docker: modify native token symbol - [#5286](https://github.com/blockscout/blockscout/pull/5286) - Change namespace for one of the SmartContractViewTest test - [#5260](https://github.com/blockscout/blockscout/pull/5260) - Makefile release task to prerelease and release task +- [#5082](https://github.com/blockscout/blockscout/pull/5082) - Elixir 1.12 -> 1.13 ## 4.1.2-beta diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index dbf91daec56c..636f9a34c5bc 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -5166,43 +5166,35 @@ defmodule Explorer.Chain do {:ok, "0x" <> token1_encoded} <- token1_signature |> Contract.eth_call_request(foreign_token_address_hash, 2, nil, nil) + |> json_rpc(eth_call_foreign_json_rpc_named_arguments), + token0_hash <- parse_contract_response(token0_encoded, :address), + token1_hash <- parse_contract_response(token1_encoded, :address), + false <- is_nil(token0_hash), + false <- is_nil(token1_hash), + token0_hash_str <- "0x" <> Base.encode16(token0_hash, case: :lower), + token1_hash_str <- "0x" <> Base.encode16(token1_hash, case: :lower), + {:ok, "0x" <> token0_name_encoded} <- + name_signature + |> Contract.eth_call_request(token0_hash_str, 1, nil, nil) + |> json_rpc(eth_call_foreign_json_rpc_named_arguments), + {:ok, "0x" <> token1_name_encoded} <- + name_signature + |> Contract.eth_call_request(token1_hash_str, 2, nil, nil) + |> json_rpc(eth_call_foreign_json_rpc_named_arguments), + {:ok, "0x" <> token0_symbol_encoded} <- + symbol_signature + |> Contract.eth_call_request(token0_hash_str, 1, nil, nil) + |> json_rpc(eth_call_foreign_json_rpc_named_arguments), + {:ok, "0x" <> token1_symbol_encoded} <- + symbol_signature + |> Contract.eth_call_request(token1_hash_str, 2, nil, nil) |> json_rpc(eth_call_foreign_json_rpc_named_arguments) do - token0_hash = parse_contract_response(token0_encoded, :address) - token1_hash = parse_contract_response(token1_encoded, :address) + token0_name = parse_contract_response(token0_name_encoded, :string, {:bytes, 32}) + token1_name = parse_contract_response(token1_name_encoded, :string, {:bytes, 32}) + token0_symbol = parse_contract_response(token0_symbol_encoded, :string, {:bytes, 32}) + token1_symbol = parse_contract_response(token1_symbol_encoded, :string, {:bytes, 32}) - if token0_hash && token1_hash do - token0_hash_str = "0x" <> Base.encode16(token0_hash, case: :lower) - token1_hash_str = "0x" <> Base.encode16(token1_hash, case: :lower) - - with {:ok, "0x" <> token0_name_encoded} <- - name_signature - |> Contract.eth_call_request(token0_hash_str, 1, nil, nil) - |> json_rpc(eth_call_foreign_json_rpc_named_arguments), - {:ok, "0x" <> token1_name_encoded} <- - name_signature - |> Contract.eth_call_request(token1_hash_str, 2, nil, nil) - |> json_rpc(eth_call_foreign_json_rpc_named_arguments), - {:ok, "0x" <> token0_symbol_encoded} <- - symbol_signature - |> Contract.eth_call_request(token0_hash_str, 1, nil, nil) - |> json_rpc(eth_call_foreign_json_rpc_named_arguments), - {:ok, "0x" <> token1_symbol_encoded} <- - symbol_signature - |> Contract.eth_call_request(token1_hash_str, 2, nil, nil) - |> json_rpc(eth_call_foreign_json_rpc_named_arguments) do - token0_name = parse_contract_response(token0_name_encoded, :string, {:bytes, 32}) - token1_name = parse_contract_response(token1_name_encoded, :string, {:bytes, 32}) - token0_symbol = parse_contract_response(token0_symbol_encoded, :string, {:bytes, 32}) - token1_symbol = parse_contract_response(token1_symbol_encoded, :string, {:bytes, 32}) - - "#{token0_name}/#{token1_name} (#{token0_symbol}/#{token1_symbol})" - else - _ -> - nil - end - else - nil - end + "#{token0_name}/#{token1_name} (#{token0_symbol}/#{token1_symbol})" else _ -> nil @@ -5309,16 +5301,14 @@ defmodule Explorer.Chain do |> parse_contract_response({:uint, 256}) |> Decimal.new() - with {:ok, "0x" <> token_encoded} <- - token_signature - |> Contract.eth_call_request(foreign_token_address_hash, 1, nil, nil) - |> json_rpc(eth_call_foreign_json_rpc_named_arguments) do - token_hash = parse_contract_response(token_encoded, :address) - - if token_hash do - token_hash_str = "0x" <> Base.encode16(token_hash, case: :lower) - - with {:ok, "0x" <> token_decimals_encoded} <- + case token_signature + |> Contract.eth_call_request(foreign_token_address_hash, 1, nil, nil) + |> json_rpc(eth_call_foreign_json_rpc_named_arguments) do + {:ok, "0x" <> token_encoded} -> + with token_hash <- parse_contract_response(token_encoded, :address), + false <- is_nil(token_hash), + token_hash_str <- "0x" <> Base.encode16(token_hash, case: :lower), + {:ok, "0x" <> token_decimals_encoded} <- decimals_signature |> Contract.eth_call_request(token_hash_str, 1, nil, nil) |> json_rpc(eth_call_foreign_json_rpc_named_arguments), @@ -5355,8 +5345,9 @@ defmodule Explorer.Chain do end {:ok, token_cap_usd} + else + _ -> :error end - end end end diff --git a/apps/indexer/lib/indexer/buffered_task.ex b/apps/indexer/lib/indexer/buffered_task.ex index f11b87d3b9c5..f1244e9753b3 100644 --- a/apps/indexer/lib/indexer/buffered_task.ex +++ b/apps/indexer/lib/indexer/buffered_task.ex @@ -403,8 +403,8 @@ defmodule Indexer.BufferedTask do " bound queue is at maximum size (", to_string(maximum_size), ") and ", - remaining_entries |> Enum.count() |> to_string() - | " entries could not be added." + remaining_entries |> Enum.count() |> to_string(), + " entries could not be added." ] end) @@ -448,8 +448,8 @@ defmodule Indexer.BufferedTask do Logger.info(fn -> [ "BufferedTask ", - process(self()) - | " ran out of work, but work queue was shrunk to save memory, so restoring lost work from `c:init/2`." + process(self()), + " ran out of work, but work queue was shrunk to save memory, so restoring lost work from `c:init/2`." ] end) diff --git a/apps/indexer/lib/indexer/memory/monitor.ex b/apps/indexer/lib/indexer/memory/monitor.ex index a63d039be284..40562a0f1330 100644 --- a/apps/indexer/lib/indexer/memory/monitor.ex +++ b/apps/indexer/lib/indexer/memory/monitor.ex @@ -157,7 +157,7 @@ defmodule Indexer.Memory.Monitor do {:error, :minimum_size} -> Logger.error(fn -> - [process(pid) | " is at its minimum size and could not shrink."] + [process(pid), " is at its minimum size and could not shrink."] end) shrink(tail) diff --git a/docker/Dockerfile b/docker/Dockerfile index b2e9a024cb40..5378f1f27fdb 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,4 +1,4 @@ -FROM bitwalker/alpine-elixir-phoenix:1.12 +FROM bitwalker/alpine-elixir-phoenix:1.13 RUN apk --no-cache --update add alpine-sdk gmp-dev automake libtool inotify-tools autoconf python3 file diff --git a/mix.lock b/mix.lock index b5b70729b71d..0a0c16a2ac9b 100644 --- a/mix.lock +++ b/mix.lock @@ -32,7 +32,7 @@ "earmark": {:hex, :earmark, "1.3.5", "0db71c8290b5bc81cb0101a2a507a76dca659513984d683119ee722828b424f6", [:mix], [], "hexpm", "762b999fd414fb41e297944228aa1de2cd4a3876a07f968c8b11d1e9a2190d07"}, "earmark_parser": {:hex, :earmark_parser, "1.4.20", "89970db71b11b6b89759ce16807e857df154f8df3e807b2920a8c39834a9e5cf", [:mix], [], "hexpm", "1eb0d2dabeeeff200e0d17dc3048a6045aab271f73ebb82e416464832eb57bdd"}, "ecto": {:hex, :ecto, "3.7.1", "a20598862351b29f80f285b21ec5297da1181c0442687f9b8329f0445d228892", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d36e5b39fc479e654cffd4dbe1865d9716e4a9b6311faff799b6f90ab81b8638"}, - "ecto_sql": {:hex, :ecto_sql, "3.7.0", "2fcaad4ab0c8d76a5afbef078162806adbe709c04160aca58400d5cbbe8eeac6", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.7.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.4.0 or ~> 0.5.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a26135dfa1d99bf87a928c464cfa25bba6535a4fe761eefa56077a4febc60f70"}, + "ecto_sql": {:hex, :ecto_sql, "3.7.1", "8de624ef50b2a8540252d8c60506379fbbc2707be1606853df371cf53df5d053", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.7.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.4.0 or ~> 0.5.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2b42a32e2ce92f64aba5c88617891ab3b0ba34f3f3a503fa20009eae1a401c81"}, "elixir_make": {:hex, :elixir_make, "0.6.2", "7dffacd77dec4c37b39af867cedaabb0b59f6a871f89722c25b28fcd4bd70530", [:mix], [], "hexpm", "03e49eadda22526a7e5279d53321d1cced6552f344ba4e03e619063de75348d9"}, "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, "ex_abi": {:hex, :ex_abi, "0.5.11", "a53307cf796231bf068a9941d57fbcb8654e72042c2a113a49f08dfb248875fb", [:mix], [{:ex_keccak, "~> 0.4.0", [hex: :ex_keccak, repo: "hexpm", optional: false]}, {:jason, "~> 1.3", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "e128577740bdc0f05ed6841cbb1c88bb80377613970ed870fa052b780870655a"}, From bbcb84fbe3b18edea7c3660e87c40c615959f600 Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Fri, 8 Apr 2022 14:19:00 +0300 Subject: [PATCH 043/128] Cache modules refactoring --- CHANGELOG.md | 1 + .../controllers/chain_controller.ex | 9 ++- .../controllers/transaction_controller.ex | 3 +- apps/explorer/config/config.exs | 15 ++-- apps/explorer/lib/explorer/application.ex | 8 +- apps/explorer/lib/explorer/chain.ex | 74 ------------------- .../chain/cache/{block_count.ex => block.ex} | 43 ++++++++++- .../lib/explorer/chain/cache/gas_usage.ex | 34 ++++++++- .../chain/cache/token_exchange_rate.ex | 59 ++++++--------- .../{transaction_count.ex => transaction.ex} | 24 +++++- .../counters/address_gas_usage_counter.ex | 39 ++-------- .../address_token_transfers_counter.ex | 47 +++--------- .../counters/address_tokens_usd_sum.ex | 39 ++-------- .../counters/address_transactions_counter.ex | 44 +++-------- .../explorer/counters/average_block_time.ex | 2 +- .../counters/block_burned_fee_counter.ex | 24 ++---- .../counters/block_priority_fee_counter.ex | 24 ++---- apps/explorer/lib/explorer/counters/helper.ex | 41 ++++++++++ .../counters/token_holders_counter.ex | 36 ++------- .../counters/token_transfers_counter.ex | 39 ++-------- .../explorer/market/market_history_cache.ex | 16 +--- .../{block_count_test.exs => block_test.exs} | 22 +++--- ...on_count_test.exs => transaction_test.exs} | 22 +++--- apps/explorer/test/explorer/chain_test.exs | 3 +- docker-compose/envs/common-blockscout.env | 32 ++++---- docker/Makefile | 60 +++++++-------- 26 files changed, 319 insertions(+), 441 deletions(-) rename apps/explorer/lib/explorer/chain/cache/{block_count.ex => block.ex} (60%) rename apps/explorer/lib/explorer/chain/cache/{transaction_count.ex => transaction.ex} (71%) create mode 100644 apps/explorer/lib/explorer/counters/helper.ex rename apps/explorer/test/explorer/chain/cache/{block_count_test.exs => block_test.exs} (58%) rename apps/explorer/test/explorer/chain/cache/{transaction_count_test.exs => transaction_test.exs} (50%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 558f12e28375..327e87ade4de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ - [#5239](https://github.com/blockscout/blockscout/pull/5239) - Add accounting for block rewards in `getblockreward` api method ### Chore +- [#5433](https://github.com/blockscout/blockscout/pull/5433) - Caching modules refactoring - [#5419](https://github.com/blockscout/blockscout/pull/5419) - Add check if address exists for some api methods - [#5408](https://github.com/blockscout/blockscout/pull/5408) - Update websocket_client hex package - [#5407](https://github.com/blockscout/blockscout/pull/5407) - Update hackney, certifi, tzdata diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/chain_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/chain_controller.ex index b3c438efd63d..f744e74bfc34 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/chain_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/chain_controller.ex @@ -6,6 +6,9 @@ defmodule BlockScoutWeb.ChainController do alias BlockScoutWeb.{ChainView, Controller} alias Explorer.{Chain, PagingOptions, Repo} alias Explorer.Chain.{Address, Block, Transaction} + alias Explorer.Chain.Cache.Block, as: BlockCache + alias Explorer.Chain.Cache.GasUsage + alias Explorer.Chain.Cache.Transaction, as: TransactionCache alias Explorer.Chain.Supply.{RSK, TokenBridge} alias Explorer.Chain.Transaction.History.TransactionStats alias Explorer.Counters.AverageBlockTime @@ -14,9 +17,9 @@ defmodule BlockScoutWeb.ChainController do alias Phoenix.View def show(conn, _params) do - transaction_estimated_count = Chain.transaction_estimated_count() - total_gas_usage = Chain.total_gas_usage() - block_count = Chain.block_estimated_count() + transaction_estimated_count = TransactionCache.estimated_count() + total_gas_usage = GasUsage.total() + block_count = BlockCache.estimated_count() address_count = Chain.address_estimated_count() market_cap_calculation = diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_controller.ex index b32a7c64137a..6ed8cf00b884 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_controller.ex @@ -12,6 +12,7 @@ defmodule BlockScoutWeb.TransactionController do alias BlockScoutWeb.{AccessHelpers, Controller, TransactionView} alias Explorer.Chain + alias Explorer.Chain.Cache.Transaction, as: TransactionCache alias Phoenix.View {:ok, burn_address_hash} = Chain.string_to_address_hash("0x0000000000000000000000000000000000000000") @@ -94,7 +95,7 @@ defmodule BlockScoutWeb.TransactionController do end def index(conn, _params) do - transaction_estimated_count = Chain.transaction_estimated_count() + transaction_estimated_count = TransactionCache.estimated_count() render( conn, diff --git a/apps/explorer/config/config.exs b/apps/explorer/config/config.exs index 6fe9b7816ecf..c8986bfab680 100644 --- a/apps/explorer/config/config.exs +++ b/apps/explorer/config/config.exs @@ -46,7 +46,7 @@ config :explorer, Explorer.Chain.Cache.BlockNumber, global_ttl: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(5)) address_sum_global_ttl = - "ADDRESS_SUM_CACHE_PERIOD" + "CACHE_ADDRESS_SUM_PERIOD" |> System.get_env("") |> Integer.parse() |> case do @@ -65,8 +65,8 @@ config :explorer, Explorer.Chain.Cache.AddressSumMinusBurnt, global_ttl: address_sum_global_ttl balances_update_interval = - if System.get_env("ADDRESS_WITH_BALANCES_UPDATE_INTERVAL") do - case Integer.parse(System.get_env("ADDRESS_WITH_BALANCES_UPDATE_INTERVAL")) do + if System.get_env("CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL") do + case Integer.parse(System.get_env("CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL")) do {integer, ""} -> integer _ -> nil end @@ -118,9 +118,12 @@ config :explorer, Explorer.Counters.BlockPriorityFeeCounter, enabled: true, enable_consolidation: true +config :explorer, Explorer.Chain.Cache.GasUsage, + enabled: System.get_env("CACHE_ENABLE_TOTAL_GAS_USAGE_COUNTER") == "true" + bridge_market_cap_update_interval = - if System.get_env("BRIDGE_MARKET_CAP_UPDATE_INTERVAL") do - case Integer.parse(System.get_env("BRIDGE_MARKET_CAP_UPDATE_INTERVAL")) do + if System.get_env("CACHE_BRIDGE_MARKET_CAP_UPDATE_INTERVAL") do + case Integer.parse(System.get_env("CACHE_BRIDGE_MARKET_CAP_UPDATE_INTERVAL")) do {integer, ""} -> integer _ -> nil end @@ -246,8 +249,6 @@ config :explorer, Explorer.Chain.Cache.Uncles, ttl_check_interval: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(1), else: false), global_ttl: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(5)) -config :explorer, Explorer.Chain.Cache.GasUsage, enabled: false - config :explorer, Explorer.ThirdPartyIntegrations.Sourcify, server_url: System.get_env("SOURCIFY_SERVER_URL") || "https://sourcify.dev/server", enabled: System.get_env("ENABLE_SOURCIFY_INTEGRATION") == "true", diff --git a/apps/explorer/lib/explorer/application.ex b/apps/explorer/lib/explorer/application.ex index a6b7e28e574b..8fa1d77db10b 100644 --- a/apps/explorer/lib/explorer/application.ex +++ b/apps/explorer/lib/explorer/application.ex @@ -11,13 +11,13 @@ defmodule Explorer.Application do Accounts, AddressSum, AddressSumMinusBurnt, - BlockCount, + Block, BlockNumber, Blocks, GasUsage, MinMissingBlockNumber, NetVersion, - TransactionCount, + Transaction, Transactions, Uncles } @@ -51,10 +51,10 @@ defmodule Explorer.Application do Explorer.SmartContract.VyperDownloader, {Registry, keys: :duplicate, name: Registry.ChainEvents, id: Registry.ChainEvents}, {Admin.Recovery, [[], [name: Admin.Recovery]]}, - TransactionCount, + Transaction, AddressSum, AddressSumMinusBurnt, - BlockCount, + Block, Blocks, GasUsage, NetVersion, diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index 636f9a34c5bc..3661350a9c63 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -28,7 +28,6 @@ defmodule Explorer.Chain do require Logger alias ABI.{TypeDecoder, TypeEncoder} - alias Ecto.Adapters.SQL alias Ecto.{Changeset, Multi} alias EthereumJSONRPC.Contract @@ -69,12 +68,9 @@ defmodule Explorer.Chain do alias Explorer.Chain.Cache.{ Accounts, - BlockCount, BlockNumber, Blocks, - GasUsage, TokenExchangeRate, - TransactionCount, Transactions, Uncles } @@ -2094,32 +2090,10 @@ defmodule Explorer.Chain do 0 end - @spec fetch_count_consensus_block() :: non_neg_integer - def fetch_count_consensus_block do - query = - from(block in Block, - select: count(block.hash), - where: block.consensus == true - ) - - Repo.one!(query, timeout: :infinity) || 0 - end - def fetch_block_by_hash(block_hash) do Repo.get(Block, block_hash) end - @spec fetch_sum_gas_used() :: non_neg_integer - def fetch_sum_gas_used do - query = - from( - t0 in Transaction, - select: fragment("SUM(t0.gas_used)") - ) - - Repo.one!(query, timeout: :infinity) || 0 - end - @doc """ The number of `t:Explorer.Chain.InternalTransaction.t/0`. @@ -3472,54 +3446,6 @@ defmodule Explorer.Chain do Hash.Full.cast(string) end - @doc """ - Estimated count of `t:Explorer.Chain.Transaction.t/0`. - - Estimated count of both collated and pending transactions using the transactions table statistics. - """ - @spec transaction_estimated_count() :: non_neg_integer() - def transaction_estimated_count do - cached_value = TransactionCount.get_count() - - if is_nil(cached_value) do - %Postgrex.Result{rows: [[rows]]} = - SQL.query!(Repo, "SELECT reltuples::BIGINT AS estimate FROM pg_class WHERE relname='transactions'") - - rows - else - cached_value - end - end - - @spec total_gas_usage() :: non_neg_integer() - def total_gas_usage do - cached_value = GasUsage.get_sum() - - if is_nil(cached_value) do - 0 - else - cached_value - end - end - - @doc """ - Estimated count of `t:Explorer.Chain.Block.t/0`. - - Estimated count of consensus blocks. - """ - @spec block_estimated_count() :: non_neg_integer() - def block_estimated_count do - cached_value = BlockCount.get_count() - - if is_nil(cached_value) do - %Postgrex.Result{rows: [[count]]} = Repo.query!("SELECT reltuples FROM pg_class WHERE relname = 'blocks';") - - trunc(count * 0.90) - else - cached_value - end - end - @doc """ `t:Explorer.Chain.InternalTransaction/0`s in `t:Explorer.Chain.Transaction.t/0` with `hash`. diff --git a/apps/explorer/lib/explorer/chain/cache/block_count.ex b/apps/explorer/lib/explorer/chain/cache/block.ex similarity index 60% rename from apps/explorer/lib/explorer/chain/cache/block_count.ex rename to apps/explorer/lib/explorer/chain/cache/block.ex index b8fae34587f7..0c3ac1242aec 100644 --- a/apps/explorer/lib/explorer/chain/cache/block_count.ex +++ b/apps/explorer/lib/explorer/chain/cache/block.ex @@ -1,10 +1,15 @@ -defmodule Explorer.Chain.Cache.BlockCount do +defmodule Explorer.Chain.Cache.Block do @moduledoc """ Cache for block count. """ @default_cache_period :timer.hours(2) + import Ecto.Query, + only: [ + from: 2 + ] + use Explorer.Chain.MapCache, name: :block_count, key: :count, @@ -15,7 +20,26 @@ defmodule Explorer.Chain.Cache.BlockCount do require Logger - alias Explorer.Chain + alias Explorer.Chain.Block + alias Explorer.Repo + + @doc """ + Estimated count of `t:Explorer.Chain.Block.t/0`. + + Estimated count of consensus blocks. + """ + @spec estimated_count() :: non_neg_integer() + def estimated_count do + cached_value = __MODULE__.get_count() + + if is_nil(cached_value) do + %Postgrex.Result{rows: [[count]]} = Repo.query!("SELECT reltuples FROM pg_class WHERE relname = 'blocks';") + + trunc(count * 0.90) + else + cached_value + end + end defp handle_fallback(:count) do # This will get the task PID if one exists and launch a new task if not @@ -31,7 +55,7 @@ defmodule Explorer.Chain.Cache.BlockCount do {:ok, task} = Task.start(fn -> try do - result = Chain.fetch_count_consensus_block() + result = fetch_count_consensus_block() set_count(result) rescue @@ -54,7 +78,7 @@ defmodule Explorer.Chain.Cache.BlockCount do defp async_task_on_deletion(_data), do: nil defp cache_period do - "BLOCK_COUNT_CACHE_PERIOD" + "CACHE_BLOCK_COUNT_PERIOD" |> System.get_env("") |> Integer.parse() |> case do @@ -62,4 +86,15 @@ defmodule Explorer.Chain.Cache.BlockCount do _ -> @default_cache_period end end + + @spec fetch_count_consensus_block() :: non_neg_integer + defp fetch_count_consensus_block do + query = + from(block in Block, + select: count(block.hash), + where: block.consensus == true + ) + + Repo.one!(query, timeout: :infinity) || 0 + end end diff --git a/apps/explorer/lib/explorer/chain/cache/gas_usage.ex b/apps/explorer/lib/explorer/chain/cache/gas_usage.ex index ca9c29b455cc..467a317631ae 100644 --- a/apps/explorer/lib/explorer/chain/cache/gas_usage.ex +++ b/apps/explorer/lib/explorer/chain/cache/gas_usage.ex @@ -5,6 +5,11 @@ defmodule Explorer.Chain.Cache.GasUsage do require Logger + import Ecto.Query, + only: [ + from: 2 + ] + @default_cache_period :timer.hours(2) config = Application.get_env(:explorer, __MODULE__) @enabled Keyword.get(config, :enabled) @@ -17,7 +22,19 @@ defmodule Explorer.Chain.Cache.GasUsage do ttl_check_interval: :timer.minutes(15), callback: &async_task_on_deletion(&1) - alias Explorer.Chain + alias Explorer.Chain.Transaction + alias Explorer.Repo + + @spec total() :: non_neg_integer() + def total do + cached_value = __MODULE__.get_sum() + + if is_nil(cached_value) do + 0 + else + cached_value + end + end defp handle_fallback(:sum) do # This will get the task PID if one exists and launch a new task if not @@ -34,7 +51,7 @@ defmodule Explorer.Chain.Cache.GasUsage do {:ok, task} = Task.start(fn -> try do - result = Chain.fetch_sum_gas_used() + result = fetch_sum_gas_used() set_sum(result) rescue @@ -60,7 +77,7 @@ defmodule Explorer.Chain.Cache.GasUsage do defp async_task_on_deletion(_data), do: nil defp cache_period do - "TOTAL_GAS_USAGE_CACHE_PERIOD" + "CACHE_TOTAL_GAS_USAGE_PERIOD" |> System.get_env("") |> Integer.parse() |> case do @@ -68,4 +85,15 @@ defmodule Explorer.Chain.Cache.GasUsage do _ -> @default_cache_period end end + + @spec fetch_sum_gas_used() :: non_neg_integer + defp fetch_sum_gas_used do + query = + from( + t0 in Transaction, + select: fragment("SUM(t0.gas_used)") + ) + + Repo.one!(query, timeout: :infinity) || 0 + end end diff --git a/apps/explorer/lib/explorer/chain/cache/token_exchange_rate.ex b/apps/explorer/lib/explorer/chain/cache/token_exchange_rate.ex index ad3f4e05c6e4..2b59ed494121 100644 --- a/apps/explorer/lib/explorer/chain/cache/token_exchange_rate.ex +++ b/apps/explorer/lib/explorer/chain/cache/token_exchange_rate.ex @@ -8,19 +8,13 @@ defmodule Explorer.Chain.Cache.TokenExchangeRate do alias Ecto.Changeset alias Explorer.Chain.BridgedToken + alias Explorer.Counters.Helper alias Explorer.ExchangeRates.Source alias Explorer.Repo @cache_name :token_exchange_rate @last_update_key "last_update" - @ets_opts [ - :set, - :named_table, - :public, - read_concurrency: true - ] - config = Application.get_env(:explorer, Explorer.Chain.Cache.TokenExchangeRate) @enable_consolidation Keyword.get(config, :enable_consolidation) @@ -62,7 +56,10 @@ defmodule Explorer.Chain.Cache.TokenExchangeRate do end) end - cached_value = fetch_from_cache(cache_key(address_hash_str)) + cached_value = + address_hash_str + |> cache_key() + |> fetch_from_cache() if is_nil(cached_value) || Decimal.cmp(cached_value, 0) == :eq do fetch_from_db(token_hash) @@ -80,7 +77,10 @@ defmodule Explorer.Chain.Cache.TokenExchangeRate do end) end - cached_value = fetch_from_cache(cache_key(symbol)) + cached_value = + symbol + |> cache_key() + |> fetch_from_cache() if is_nil(cached_value) || Decimal.cmp(cached_value, 0) == :eq do fetch_from_db(token_hash) @@ -97,18 +97,22 @@ defmodule Explorer.Chain.Cache.TokenExchangeRate do cond do is_nil(updated_at) -> true - current_time() - updated_at > cache_period -> true + Helper.current_time() - updated_at > cache_period -> true true -> false end end defp value_is_empty?(symbol_or_address_hash_str) do - value = fetch_from_cache(cache_key(symbol_or_address_hash_str)) + value = + symbol_or_address_hash_str + |> cache_key() + |> fetch_from_cache() + is_nil(value) || value == 0 end defp update_cache_by_symbol(token_hash, symbol) do - put_into_cache("#{cache_key(symbol)}_#{@last_update_key}", current_time()) + put_into_cache("#{cache_key(symbol)}_#{@last_update_key}", Helper.current_time()) exchange_rate = fetch_token_exchange_rate(symbol) @@ -117,7 +121,7 @@ defmodule Explorer.Chain.Cache.TokenExchangeRate do end defp update_cache_by_address_hash_str(token_hash, address_hash_str) do - put_into_cache("#{cache_key(address_hash_str)}_#{@last_update_key}", current_time()) + put_into_cache("#{cache_key(address_hash_str)}_#{@last_update_key}", Helper.current_time()) exchange_rate = fetch_token_exchange_rate_by_address(address_hash_str) @@ -145,16 +149,6 @@ defmodule Explorer.Chain.Cache.TokenExchangeRate do end end - defp fetch_from_cache(key) do - case :ets.lookup(@cache_name, key) do - [{_, value}] -> - value - - [] -> - 0 - end - end - defp fetch_from_db(nil), do: nil defp fetch_from_db(token_hash) do @@ -167,6 +161,10 @@ defmodule Explorer.Chain.Cache.TokenExchangeRate do end end + defp fetch_from_cache(key) do + Helper.fetch_from_cache(key, @cache_name) + end + def put_into_cache(key, value) do if cache_table_exists?() do :ets.insert(@cache_name, {key, value}) @@ -193,28 +191,17 @@ defmodule Explorer.Chain.Cache.TokenExchangeRate do |> Repo.one() end - defp current_time do - utc_now = DateTime.utc_now() - - DateTime.to_unix(utc_now, :millisecond) - end - def cache_table_exists? do :ets.whereis(@cache_name) !== :undefined end def create_cache_table do - unless cache_table_exists?() do - :ets.new(@cache_name, @ets_opts) - end + Helper.create_cache_table(@cache_name) end def enable_consolidation?, do: @enable_consolidation defp token_exchange_rate_cache_period do - case Integer.parse(System.get_env("TOKEN_EXCHANGE_RATE_CACHE_PERIOD", "")) do - {secs, ""} -> :timer.seconds(secs) - _ -> :timer.hours(1) - end + Helper.cache_period("CACHE_TOKEN_EXCHANGE_RATE_PERIOD", 1) end end diff --git a/apps/explorer/lib/explorer/chain/cache/transaction_count.ex b/apps/explorer/lib/explorer/chain/cache/transaction.ex similarity index 71% rename from apps/explorer/lib/explorer/chain/cache/transaction_count.ex rename to apps/explorer/lib/explorer/chain/cache/transaction.ex index e850310bca50..a386127aa3e0 100644 --- a/apps/explorer/lib/explorer/chain/cache/transaction_count.ex +++ b/apps/explorer/lib/explorer/chain/cache/transaction.ex @@ -1,4 +1,4 @@ -defmodule Explorer.Chain.Cache.TransactionCount do +defmodule Explorer.Chain.Cache.Transaction do @moduledoc """ Cache for estimated transaction count. """ @@ -15,9 +15,29 @@ defmodule Explorer.Chain.Cache.TransactionCount do require Logger + alias Ecto.Adapters.SQL alias Explorer.Chain.Transaction alias Explorer.Repo + @doc """ + Estimated count of `t:Explorer.Chain.Transaction.t/0`. + + Estimated count of both collated and pending transactions using the transactions table statistics. + """ + @spec estimated_count() :: non_neg_integer() + def estimated_count do + cached_value = __MODULE__.get_count() + + if is_nil(cached_value) do + %Postgrex.Result{rows: [[rows]]} = + SQL.query!(Repo, "SELECT reltuples::BIGINT AS estimate FROM pg_class WHERE relname='transactions'") + + rows + else + cached_value + end + end + defp handle_fallback(:count) do # This will get the task PID if one exists and launch a new task if not # See next `handle_fallback` definition @@ -55,7 +75,7 @@ defmodule Explorer.Chain.Cache.TransactionCount do defp async_task_on_deletion(_data), do: nil defp cache_period do - "TXS_COUNT_CACHE_PERIOD" + "CACHE_TXS_COUNT_PERIOD" |> System.get_env("") |> Integer.parse() |> case do diff --git a/apps/explorer/lib/explorer/counters/address_gas_usage_counter.ex b/apps/explorer/lib/explorer/counters/address_gas_usage_counter.ex index 5dd1a825b10a..2572360f8eaf 100644 --- a/apps/explorer/lib/explorer/counters/address_gas_usage_counter.ex +++ b/apps/explorer/lib/explorer/counters/address_gas_usage_counter.ex @@ -6,17 +6,11 @@ defmodule Explorer.Counters.AddressTransactionsGasUsageCounter do alias Ecto.Changeset alias Explorer.{Chain, Repo} + alias Explorer.Counters.Helper @cache_name :address_transactions_gas_usage_counter @last_update_key "last_update" - @ets_opts [ - :set, - :named_table, - :public, - read_concurrency: true - ] - config = Application.get_env(:explorer, __MODULE__) @enable_consolidation Keyword.get(config, :enable_consolidation) @@ -65,27 +59,21 @@ defmodule Explorer.Counters.AddressTransactionsGasUsageCounter do cond do is_nil(updated_at) -> true - current_time() - updated_at > cache_period -> true + Helper.current_time() - updated_at > cache_period -> true true -> false end end defp update_cache(address) do address_hash_string = to_string(address.hash) - put_into_cache("hash_#{address_hash_string}_#{@last_update_key}", current_time()) + put_into_cache("hash_#{address_hash_string}_#{@last_update_key}", Helper.current_time()) new_data = Chain.address_to_gas_usage_count(address) put_into_cache("hash_#{address_hash_string}", new_data) put_into_db(address, new_data) end defp fetch_from_cache(key) do - case :ets.lookup(@cache_name, key) do - [{_, value}] -> - value - - [] -> - 0 - end + Helper.fetch_from_cache(key, @cache_name) end defp put_into_cache(key, value) do @@ -100,24 +88,13 @@ defmodule Explorer.Counters.AddressTransactionsGasUsageCounter do |> Repo.update() end - defp current_time do - utc_now = DateTime.utc_now() - - DateTime.to_unix(utc_now, :millisecond) - end - - def create_cache_table do - if :ets.whereis(@cache_name) == :undefined do - :ets.new(@cache_name, @ets_opts) - end + defp create_cache_table do + Helper.create_cache_table(@cache_name) end - def enable_consolidation?, do: @enable_consolidation + defp enable_consolidation?, do: @enable_consolidation defp address_transactions_gas_usage_counter_cache_period do - case Integer.parse(System.get_env("ADDRESS_TRANSACTIONS_GAS_USAGE_COUNTER_CACHE_PERIOD", "")) do - {secs, ""} -> :timer.seconds(secs) - _ -> :timer.hours(1) - end + Helper.cache_period("CACHE_ADDRESS_TRANSACTIONS_GAS_USAGE_COUNTER_PERIOD", 1) end end diff --git a/apps/explorer/lib/explorer/counters/address_token_transfers_counter.ex b/apps/explorer/lib/explorer/counters/address_token_transfers_counter.ex index 3cad4650c599..409030e18bf4 100644 --- a/apps/explorer/lib/explorer/counters/address_token_transfers_counter.ex +++ b/apps/explorer/lib/explorer/counters/address_token_transfers_counter.ex @@ -6,17 +6,11 @@ defmodule Explorer.Counters.AddressTokenTransfersCounter do alias Ecto.Changeset alias Explorer.{Chain, Repo} + alias Explorer.Counters.Helper @cache_name :address_token_transfers_counter @last_update_key "last_update" - @ets_opts [ - :set, - :named_table, - :public, - read_concurrency: true - ] - config = Application.get_env(:explorer, __MODULE__) @enable_consolidation Keyword.get(config, :enable_consolidation) @@ -65,57 +59,40 @@ defmodule Explorer.Counters.AddressTokenTransfersCounter do cond do is_nil(updated_at) -> true - current_time() - updated_at > cache_period -> true + Helper.current_time() - updated_at > cache_period -> true true -> false end end defp update_cache(address) do address_hash_string = to_string(address.hash) - put_into_cache("hash_#{address_hash_string}_#{@last_update_key}", current_time()) + put_into_cache("hash_#{address_hash_string}_#{@last_update_key}", Helper.current_time()) new_data = Chain.address_to_token_transfer_count(address) put_into_cache("hash_#{address_hash_string}", new_data) put_into_db(address, new_data) end defp fetch_from_cache(key) do - case :ets.lookup(@cache_name, key) do - [{_, value}] -> - value - - [] -> - 0 - end + Helper.fetch_from_cache(key, @cache_name) end defp put_into_cache(key, value) do :ets.insert(@cache_name, {key, value}) end - defp current_time do - utc_now = DateTime.utc_now() - - DateTime.to_unix(utc_now, :millisecond) + defp put_into_db(address, value) do + address + |> Changeset.change(%{token_transfers_count: value}) + |> Repo.update() end - def create_cache_table do - if :ets.whereis(@cache_name) == :undefined do - :ets.new(@cache_name, @ets_opts) - end + defp create_cache_table do + Helper.create_cache_table(@cache_name) end - def enable_consolidation?, do: @enable_consolidation + defp enable_consolidation?, do: @enable_consolidation defp address_token_transfers_counter_cache_period do - case Integer.parse(System.get_env("ADDRESS_TOKEN_TRANSFERS_COUNTER_CACHE_PERIOD", "")) do - {secs, ""} -> :timer.seconds(secs) - _ -> :timer.hours(1) - end - end - - defp put_into_db(address, value) do - address - |> Changeset.change(%{token_transfers_count: value}) - |> Repo.update() + Helper.cache_period("CACHE_ADDRESS_TOKEN_TRANSFERS_COUNTER_PERIOD", 1) end end diff --git a/apps/explorer/lib/explorer/counters/address_tokens_usd_sum.ex b/apps/explorer/lib/explorer/counters/address_tokens_usd_sum.ex index db1f3830686a..e0e5f9c9a268 100644 --- a/apps/explorer/lib/explorer/counters/address_tokens_usd_sum.ex +++ b/apps/explorer/lib/explorer/counters/address_tokens_usd_sum.ex @@ -5,17 +5,11 @@ defmodule Explorer.Counters.AddressTokenUsdSum do use GenServer alias Explorer.Chain + alias Explorer.Counters.Helper @cache_name :address_tokens_usd_value @last_update_key "last_update" - @ets_opts [ - :set, - :named_table, - :public, - read_concurrency: true - ] - config = Application.get_env(:explorer, Explorer.Counters.AddressTokenUsdSum) @enable_consolidation Keyword.get(config, :enable_consolidation) @@ -64,49 +58,32 @@ defmodule Explorer.Counters.AddressTokenUsdSum do cond do is_nil(updated_at) -> true - current_time() - updated_at > cache_period -> true + Helper.current_time() - updated_at > cache_period -> true true -> false end end defp update_cache(address_hash_string, token_balances) do - put_into_cache("hash_#{address_hash_string}_#{@last_update_key}", current_time()) + put_into_cache("hash_#{address_hash_string}_#{@last_update_key}", Helper.current_time()) new_data = Chain.address_tokens_usd_sum(token_balances) put_into_cache("hash_#{address_hash_string}", new_data) end defp fetch_from_cache(key) do - case :ets.lookup(@cache_name, key) do - [{_, value}] -> - value - - [] -> - 0 - end + Helper.fetch_from_cache(key, @cache_name) end defp put_into_cache(key, value) do :ets.insert(@cache_name, {key, value}) end - defp current_time do - utc_now = DateTime.utc_now() - - DateTime.to_unix(utc_now, :millisecond) - end - - def create_cache_table do - if :ets.whereis(@cache_name) == :undefined do - :ets.new(@cache_name, @ets_opts) - end + defp create_cache_table do + Helper.create_cache_table(@cache_name) end - def enable_consolidation?, do: @enable_consolidation + defp enable_consolidation?, do: @enable_consolidation defp address_tokens_usd_sum_cache_period do - case Integer.parse(System.get_env("ADDRESS_TOKENS_USD_SUM_CACHE_PERIOD", "")) do - {secs, ""} -> :timer.seconds(secs) - _ -> :timer.hours(1) - end + Helper.cache_period("CACHE_ADDRESS_TOKENS_USD_SUM_PERIOD", 1) end end diff --git a/apps/explorer/lib/explorer/counters/address_transactions_counter.ex b/apps/explorer/lib/explorer/counters/address_transactions_counter.ex index 0ad5dc655a9d..bcd0a71207eb 100644 --- a/apps/explorer/lib/explorer/counters/address_transactions_counter.ex +++ b/apps/explorer/lib/explorer/counters/address_transactions_counter.ex @@ -6,17 +6,11 @@ defmodule Explorer.Counters.AddressTransactionsCounter do alias Ecto.Changeset alias Explorer.{Chain, Repo} + alias Explorer.Counters.Helper @cache_name :address_transactions_counter @last_update_key "last_update" - @ets_opts [ - :set, - :named_table, - :public, - read_concurrency: true - ] - config = Application.get_env(:explorer, __MODULE__) @enable_consolidation Keyword.get(config, :enable_consolidation) @@ -65,57 +59,43 @@ defmodule Explorer.Counters.AddressTransactionsCounter do cond do is_nil(updated_at) -> true - current_time() - updated_at > cache_period -> true + Helper.current_time() - updated_at > cache_period -> true true -> false end end defp update_cache(address) do address_hash_string = to_string(address.hash) - put_into_cache("hash_#{address_hash_string}_#{@last_update_key}", current_time()) + put_into_cache("hash_#{address_hash_string}_#{@last_update_key}", Helper.current_time()) new_data = Chain.address_to_transaction_count(address) put_into_cache("hash_#{address_hash_string}", new_data) put_into_db(address, new_data) end defp fetch_from_cache(key) do - case :ets.lookup(@cache_name, key) do - [{_, value}] -> - value - - [] -> - 0 - end + Helper.fetch_from_cache(key, @cache_name) end defp put_into_cache(key, value) do :ets.insert(@cache_name, {key, value}) end - defp current_time do - utc_now = DateTime.utc_now() - - DateTime.to_unix(utc_now, :millisecond) + defp put_into_db(address, value) do + address + |> Changeset.change(%{transactions_count: value}) + |> Repo.update() end - def create_cache_table do - if :ets.whereis(@cache_name) == :undefined do - :ets.new(@cache_name, @ets_opts) - end + defp create_cache_table do + Helper.create_cache_table(@cache_name) end - def enable_consolidation?, do: @enable_consolidation + defp enable_consolidation?, do: @enable_consolidation defp address_transactions_counter_cache_period do - case Integer.parse(System.get_env("ADDRESS_TRANSACTIONS_COUNTER_CACHE_PERIOD", "")) do + case Integer.parse(System.get_env("CACHE_ADDRESS_TRANSACTIONS_COUNTER_PERIOD", "")) do {secs, ""} -> :timer.seconds(secs) _ -> :timer.hours(1) end end - - defp put_into_db(address, value) do - address - |> Changeset.change(%{transactions_count: value}) - |> Repo.update() - end end diff --git a/apps/explorer/lib/explorer/counters/average_block_time.ex b/apps/explorer/lib/explorer/counters/average_block_time.ex index b351f0799586..81142283d887 100644 --- a/apps/explorer/lib/explorer/counters/average_block_time.ex +++ b/apps/explorer/lib/explorer/counters/average_block_time.ex @@ -130,7 +130,7 @@ defmodule Explorer.Counters.AverageBlockTime do end defp average_block_cache_period do - case Integer.parse(System.get_env("AVERAGE_BLOCK_CACHE_PERIOD", "")) do + case Integer.parse(System.get_env("CACE_AVERAGE_BLOCK_PERIOD", "")) do {secs, ""} -> :timer.seconds(secs) _ -> :timer.minutes(30) end diff --git a/apps/explorer/lib/explorer/counters/block_burned_fee_counter.ex b/apps/explorer/lib/explorer/counters/block_burned_fee_counter.ex index eee5a97f1504..5726bf6e0a55 100644 --- a/apps/explorer/lib/explorer/counters/block_burned_fee_counter.ex +++ b/apps/explorer/lib/explorer/counters/block_burned_fee_counter.ex @@ -5,16 +5,10 @@ defmodule Explorer.Counters.BlockBurnedFeeCounter do use GenServer alias Explorer.Chain + alias Explorer.Counters.Helper @cache_name :block_burned_fee_counter - @ets_opts [ - :set, - :named_table, - :public, - read_concurrency: true - ] - config = Application.get_env(:explorer, Explorer.Counters.BlockBurnedFeeCounter) @enable_consolidation Keyword.get(config, :enable_consolidation) @@ -68,13 +62,7 @@ defmodule Explorer.Counters.BlockBurnedFeeCounter do end defp fetch_from_cache(key) do - case :ets.lookup(@cache_name, key) do - [{_, value}] -> - value - - [] -> - 0 - end + Helper.fetch_from_cache(key, @cache_name) end defp put_into_cache(key, value) do @@ -85,11 +73,9 @@ defmodule Explorer.Counters.BlockBurnedFeeCounter do Base.encode16(block_hash.bytes, case: :lower) end - def create_cache_table do - if :ets.whereis(@cache_name) == :undefined do - :ets.new(@cache_name, @ets_opts) - end + defp create_cache_table do + Helper.create_cache_table(@cache_name) end - def enable_consolidation?, do: @enable_consolidation + defp enable_consolidation?, do: @enable_consolidation end diff --git a/apps/explorer/lib/explorer/counters/block_priority_fee_counter.ex b/apps/explorer/lib/explorer/counters/block_priority_fee_counter.ex index ad0c5d48d913..54df5a858204 100644 --- a/apps/explorer/lib/explorer/counters/block_priority_fee_counter.ex +++ b/apps/explorer/lib/explorer/counters/block_priority_fee_counter.ex @@ -5,16 +5,10 @@ defmodule Explorer.Counters.BlockPriorityFeeCounter do use GenServer alias Explorer.Chain + alias Explorer.Counters.Helper @cache_name :block_priority_fee_counter - @ets_opts [ - :set, - :named_table, - :public, - read_concurrency: true - ] - config = Application.get_env(:explorer, Explorer.Counters.BlockPriorityFeeCounter) @enable_consolidation Keyword.get(config, :enable_consolidation) @@ -68,13 +62,7 @@ defmodule Explorer.Counters.BlockPriorityFeeCounter do end defp fetch_from_cache(key) do - case :ets.lookup(@cache_name, key) do - [{_, value}] -> - value - - [] -> - 0 - end + Helper.fetch_from_cache(key, @cache_name) end defp put_into_cache(key, value) do @@ -85,11 +73,9 @@ defmodule Explorer.Counters.BlockPriorityFeeCounter do Base.encode16(block_hash.bytes, case: :lower) end - def create_cache_table do - if :ets.whereis(@cache_name) == :undefined do - :ets.new(@cache_name, @ets_opts) - end + defp create_cache_table do + Helper.create_cache_table(@cache_name) end - def enable_consolidation?, do: @enable_consolidation + defp enable_consolidation?, do: @enable_consolidation end diff --git a/apps/explorer/lib/explorer/counters/helper.ex b/apps/explorer/lib/explorer/counters/helper.ex new file mode 100644 index 000000000000..9a8766d32a7b --- /dev/null +++ b/apps/explorer/lib/explorer/counters/helper.ex @@ -0,0 +1,41 @@ +defmodule Explorer.Counters.Helper do + @moduledoc """ + A helper for caching modules + """ + + @ets_opts [ + :set, + :named_table, + :public, + read_concurrency: true + ] + + def current_time do + utc_now = DateTime.utc_now() + + DateTime.to_unix(utc_now, :millisecond) + end + + def cache_period(env_var, default_hours) do + case Integer.parse(System.get_env(env_var, "")) do + {secs, ""} -> :timer.seconds(secs) + _ -> :timer.hours(default_hours) + end + end + + def fetch_from_cache(key, cache_name) do + case :ets.lookup(cache_name, key) do + [{_, value}] -> + value + + [] -> + 0 + end + end + + def create_cache_table(cache_name) do + if :ets.whereis(cache_name) == :undefined do + :ets.new(cache_name, @ets_opts) + end + end +end diff --git a/apps/explorer/lib/explorer/counters/token_holders_counter.ex b/apps/explorer/lib/explorer/counters/token_holders_counter.ex index 98c7164bc535..2959f59f0d6b 100644 --- a/apps/explorer/lib/explorer/counters/token_holders_counter.ex +++ b/apps/explorer/lib/explorer/counters/token_holders_counter.ex @@ -5,17 +5,11 @@ defmodule Explorer.Counters.TokenHoldersCounter do use GenServer alias Explorer.Chain + alias Explorer.Counters.Helper @cache_name :token_holders_counter @last_update_key "last_update" - @ets_opts [ - :set, - :named_table, - :public, - read_concurrency: true - ] - config = Application.get_env(:explorer, Explorer.Counters.TokenHoldersCounter) @enable_consolidation Keyword.get(config, :enable_consolidation) @@ -64,48 +58,34 @@ defmodule Explorer.Counters.TokenHoldersCounter do cond do is_nil(updated_at) -> true - current_time() - updated_at > cache_period -> true + Helper.current_time() - updated_at > cache_period -> true true -> false end end defp update_cache(address_hash) do address_hash_string = to_string(address_hash) - put_into_cache("hash_#{address_hash_string}_#{@last_update_key}", current_time()) + put_into_cache("hash_#{address_hash_string}_#{@last_update_key}", Helper.current_time()) new_data = Chain.count_token_holders_from_token_hash(address_hash) put_into_cache("hash_#{address_hash_string}", new_data) end defp fetch_from_cache(key) do - case :ets.lookup(@cache_name, key) do - [{_, value}] -> - value - - [] -> - 0 - end + Helper.fetch_from_cache(key, @cache_name) end defp put_into_cache(key, value) do :ets.insert(@cache_name, {key, value}) end - defp current_time do - utc_now = DateTime.utc_now() - - DateTime.to_unix(utc_now, :millisecond) - end - - def create_cache_table do - if :ets.whereis(@cache_name) == :undefined do - :ets.new(@cache_name, @ets_opts) - end + defp create_cache_table do + Helper.create_cache_table(@cache_name) end - def enable_consolidation?, do: @enable_consolidation + defp enable_consolidation?, do: @enable_consolidation defp token_holders_counter_cache_period do - case Integer.parse(System.get_env("TOKEN_HOLDERS_COUNTER_CACHE_PERIOD", "")) do + case Integer.parse(System.get_env("CACHE_TOKEN_HOLDERS_COUNTER_PERIOD", "")) do {secs, ""} -> :timer.seconds(secs) _ -> :timer.hours(1) end diff --git a/apps/explorer/lib/explorer/counters/token_transfers_counter.ex b/apps/explorer/lib/explorer/counters/token_transfers_counter.ex index 856c81b68eab..8ed6d9effadc 100644 --- a/apps/explorer/lib/explorer/counters/token_transfers_counter.ex +++ b/apps/explorer/lib/explorer/counters/token_transfers_counter.ex @@ -5,17 +5,11 @@ defmodule Explorer.Counters.TokenTransfersCounter do use GenServer alias Explorer.Chain + alias Explorer.Counters.Helper @cache_name :token_transfers_counter @last_update_key "last_update" - @ets_opts [ - :set, - :named_table, - :public, - read_concurrency: true - ] - config = Application.get_env(:explorer, Explorer.Counters.TokenTransfersCounter) @enable_consolidation Keyword.get(config, :enable_consolidation) @@ -64,50 +58,33 @@ defmodule Explorer.Counters.TokenTransfersCounter do cond do is_nil(updated_at) -> true - current_time() - updated_at > cache_period -> true + Helper.current_time() - updated_at > cache_period -> true true -> false end end defp update_cache(address_hash) do address_hash_string = to_string(address_hash) - put_into_cache("hash_#{address_hash_string}_#{@last_update_key}", current_time()) + put_into_cache("hash_#{address_hash_string}_#{@last_update_key}", Helper.current_time()) new_data = Chain.count_token_transfers_from_token_hash(address_hash) put_into_cache("hash_#{address_hash_string}", new_data) end defp fetch_from_cache(key) do - case :ets.lookup(@cache_name, key) do - [{_, value}] -> - value - - [] -> - 0 - end + Helper.fetch_from_cache(key, @cache_name) end defp put_into_cache(key, value) do :ets.insert(@cache_name, {key, value}) end - defp current_time do - utc_now = DateTime.utc_now() - - DateTime.to_unix(utc_now, :millisecond) - end - - def create_cache_table do - if :ets.whereis(@cache_name) == :undefined do - :ets.new(@cache_name, @ets_opts) - end + defp create_cache_table do + Helper.create_cache_table(@cache_name) end - def enable_consolidation?, do: @enable_consolidation + defp enable_consolidation?, do: @enable_consolidation defp token_transfers_counter_cache_period do - case Integer.parse(System.get_env("TOKEN_TRANSFERS_COUNTER_CACHE_PERIOD", "")) do - {secs, ""} -> :timer.seconds(secs) - _ -> :timer.hours(1) - end + Helper.cache_period("CACHE_TOKEN_TRANSFERS_COUNTER_PERIOD", 1) end end diff --git a/apps/explorer/lib/explorer/market/market_history_cache.ex b/apps/explorer/lib/explorer/market/market_history_cache.ex index ddaeb987c71c..55db8e5514a4 100644 --- a/apps/explorer/lib/explorer/market/market_history_cache.ex +++ b/apps/explorer/lib/explorer/market/market_history_cache.ex @@ -5,6 +5,7 @@ defmodule Explorer.Market.MarketHistoryCache do import Ecto.Query, only: [from: 2] + alias Explorer.Counters.Helper alias Explorer.Market.MarketHistory alias Explorer.Repo @@ -36,7 +37,7 @@ defmodule Explorer.Market.MarketHistoryCache do cond do is_nil(updated_at) -> true - current_time() - updated_at > cache_period -> true + Helper.current_time() - updated_at > cache_period -> true true -> false end end @@ -44,7 +45,7 @@ defmodule Explorer.Market.MarketHistoryCache do defp update_cache do new_data = fetch_from_db() - put_into_cache(@last_update_key, current_time()) + put_into_cache(@last_update_key, Helper.current_time()) put_into_cache(@history_key, new_data) new_data @@ -71,16 +72,7 @@ defmodule Explorer.Market.MarketHistoryCache do ConCache.put(@cache_name, key, value) end - defp current_time do - utc_now = DateTime.utc_now() - - DateTime.to_unix(utc_now, :millisecond) - end - defp market_history_cache_period do - case Integer.parse(System.get_env("MARKET_HISTORY_CACHE_PERIOD", "")) do - {secs, ""} -> :timer.seconds(secs) - _ -> :timer.hours(6) - end + Helper.cache_period("CACHE_MARKET_HISTORY_PERIOD", 6) end end diff --git a/apps/explorer/test/explorer/chain/cache/block_count_test.exs b/apps/explorer/test/explorer/chain/cache/block_test.exs similarity index 58% rename from apps/explorer/test/explorer/chain/cache/block_count_test.exs rename to apps/explorer/test/explorer/chain/cache/block_test.exs index 19573a7a1622..39a5da93ee59 100644 --- a/apps/explorer/test/explorer/chain/cache/block_count_test.exs +++ b/apps/explorer/test/explorer/chain/cache/block_test.exs @@ -1,16 +1,16 @@ -defmodule Explorer.Chain.Cache.BlockCountTest do +defmodule Explorer.Chain.Cache.BlockTest do use Explorer.DataCase - alias Explorer.Chain.Cache.BlockCount + alias Explorer.Chain.Cache.Block setup do - Supervisor.terminate_child(Explorer.Supervisor, BlockCount.child_id()) - Supervisor.restart_child(Explorer.Supervisor, BlockCount.child_id()) + Supervisor.terminate_child(Explorer.Supervisor, Block.child_id()) + Supervisor.restart_child(Explorer.Supervisor, Block.child_id()) :ok end test "returns default block count" do - result = BlockCount.get_count() + result = Block.get_count() assert is_nil(result) end @@ -20,11 +20,11 @@ defmodule Explorer.Chain.Cache.BlockCountTest do insert(:block, consensus: true) insert(:block, consensus: false) - _result = BlockCount.get_count() + _result = Block.get_count() Process.sleep(1000) - updated_value = BlockCount.get_count() + updated_value = Block.get_count() assert updated_value == 2 end @@ -34,22 +34,22 @@ defmodule Explorer.Chain.Cache.BlockCountTest do insert(:block, consensus: true) insert(:block, consensus: false) - _result = BlockCount.get_count() + _result = Block.get_count() Process.sleep(1000) - updated_value = BlockCount.get_count() + updated_value = Block.get_count() assert updated_value == 2 insert(:block, consensus: true) insert(:block, consensus: true) - _updated_value = BlockCount.get_count() + _updated_value = Block.get_count() Process.sleep(1000) - updated_value = BlockCount.get_count() + updated_value = Block.get_count() assert updated_value == 2 end diff --git a/apps/explorer/test/explorer/chain/cache/transaction_count_test.exs b/apps/explorer/test/explorer/chain/cache/transaction_test.exs similarity index 50% rename from apps/explorer/test/explorer/chain/cache/transaction_count_test.exs rename to apps/explorer/test/explorer/chain/cache/transaction_test.exs index 5385492de7e3..9d692d4e06c4 100644 --- a/apps/explorer/test/explorer/chain/cache/transaction_count_test.exs +++ b/apps/explorer/test/explorer/chain/cache/transaction_test.exs @@ -1,16 +1,16 @@ -defmodule Explorer.Chain.Cache.TransactionCountTest do +defmodule Explorer.Chain.Cache.TransactionTest do use Explorer.DataCase - alias Explorer.Chain.Cache.TransactionCount + alias Explorer.Chain.Cache.Transaction setup do - Supervisor.terminate_child(Explorer.Supervisor, TransactionCount.child_id()) - Supervisor.restart_child(Explorer.Supervisor, TransactionCount.child_id()) + Supervisor.terminate_child(Explorer.Supervisor, Transaction.child_id()) + Supervisor.restart_child(Explorer.Supervisor, Transaction.child_id()) :ok end test "returns default transaction count" do - result = TransactionCount.get_count() + result = Transaction.get_count() assert is_nil(result) end @@ -19,11 +19,11 @@ defmodule Explorer.Chain.Cache.TransactionCountTest do insert(:transaction) insert(:transaction) - _result = TransactionCount.get_count() + _result = Transaction.get_count() Process.sleep(1000) - updated_value = TransactionCount.get_count() + updated_value = Transaction.get_count() assert updated_value == 2 end @@ -32,22 +32,22 @@ defmodule Explorer.Chain.Cache.TransactionCountTest do insert(:transaction) insert(:transaction) - _result = TransactionCount.get_count() + _result = Transaction.get_count() Process.sleep(1000) - updated_value = TransactionCount.get_count() + updated_value = Transaction.get_count() assert updated_value == 2 insert(:transaction) insert(:transaction) - _updated_value = TransactionCount.get_count() + _updated_value = Transaction.get_count() Process.sleep(1000) - updated_value = TransactionCount.get_count() + updated_value = Transaction.get_count() assert updated_value == 2 end diff --git a/apps/explorer/test/explorer/chain_test.exs b/apps/explorer/test/explorer/chain_test.exs index 75b3d0d9b333..4cfdf6dc55de 100644 --- a/apps/explorer/test/explorer/chain_test.exs +++ b/apps/explorer/test/explorer/chain_test.exs @@ -28,6 +28,7 @@ defmodule Explorer.ChainTest do } alias Explorer.{Chain, Etherscan} + alias Explorer.Chain.Cache.Transaction, as: TransactionCache alias Explorer.Chain.InternalTransaction.Type alias Explorer.Chain.Supply.ProofOfAuthority @@ -2513,7 +2514,7 @@ defmodule Explorer.ChainTest do describe "transaction_estimated_count/1" do test "returns integer" do - assert is_integer(Chain.transaction_estimated_count()) + assert is_integer(TransactionCache.estimated_count()) end end diff --git a/docker-compose/envs/common-blockscout.env b/docker-compose/envs/common-blockscout.env index b1db041e59ea..64fac7b49c72 100644 --- a/docker-compose/envs/common-blockscout.env +++ b/docker-compose/envs/common-blockscout.env @@ -50,23 +50,23 @@ BLOCK_TRANSFORMER=base LINK_TO_OTHER_EXPLORERS=false OTHER_EXPLORERS={} SUPPORTED_CHAINS={} -BLOCK_COUNT_CACHE_PERIOD=7200 -TXS_COUNT_CACHE_PERIOD=7200 -ADDRESS_COUNT_CACHE_PERIOD=7200 -ADDRESS_SUM_CACHE_PERIOD=3600 -TOTAL_GAS_USAGE_CACHE_PERIOD=3600 -ADDRESS_TRANSACTIONS_GAS_USAGE_COUNTER_CACHE_PERIOD=1800 -TOKEN_HOLDERS_COUNTER_CACHE_PERIOD=3600 -TOKEN_TRANSFERS_COUNTER_CACHE_PERIOD=3600 -ADDRESS_WITH_BALANCES_UPDATE_INTERVAL=1800 +CACHE_BLOCK_COUNT_PERIOD=7200 +CACHE_TXS_COUNT_PERIOD=7200 +CACHE_ADDRESS_COUNT_PERIOD=7200 +CACHE_ADDRESS_SUM_PERIOD=3600 +CACHE_TOTAL_GAS_USAGE_PERIOD=3600 +CACHE_ADDRESS_TRANSACTIONS_GAS_USAGE_COUNTER_PERIOD=1800 +CACHE_TOKEN_HOLDERS_COUNTER_PERIOD=3600 +CACHE_TOKEN_TRANSFERS_COUNTER_PERIOD=3600 +CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL=1800 +CACHE_AVERAGE_BLOCK_PERIOD=1800 +CACHE_MARKET_HISTORY_PERIOD=21600 +CACHE_ADDRESS_TRANSACTIONS_PERIOD=1800 +CACHE_ADDRESS_TOKENS_USD_SUM_PERIOD=1800 +CACHE_ADDRESS_TOKEN_TRANSFERS_COUNTER_PERIOD=1800 +CACHE_BRIDGE_MARKET_CAP_UPDATE_INTERVAL=1800 +CACHE_TOKEN_EXCHANGE_RATE_PERIOD=1800 TOKEN_METADATA_UPDATE_INTERVAL=172800 -AVERAGE_BLOCK_CACHE_PERIOD=1800 -MARKET_HISTORY_CACHE_PERIOD=21600 -ADDRESS_TRANSACTIONS_CACHE_PERIOD=1800 -ADDRESS_TOKENS_USD_SUM_CACHE_PERIOD=1800 -ADDRESS_TOKEN_TRANSFERS_COUNTER_CACHE_PERIOD=1800 -BRIDGE_MARKET_CAP_UPDATE_INTERVAL=1800 -TOKEN_EXCHANGE_RATE_CACHE_PERIOD=1800 ALLOWED_EVM_VERSIONS=homestead,tangerineWhistle,spuriousDragon,byzantium,constantinople,petersburg,istanbul,berlin,london,default UNCLES_IN_AVERAGE_BLOCK_TIME=false DISABLE_WEBAPP=false diff --git a/docker/Makefile b/docker/Makefile index a9439db24bbe..86cae05a182d 100644 --- a/docker/Makefile +++ b/docker/Makefile @@ -133,11 +133,11 @@ endif ifdef TRACE_LAST_BLOCK BLOCKSCOUT_CONTAINER_PARAMS += -e 'TRACE_LAST_BLOCK=$(TRACE_LAST_BLOCK)' endif -ifdef TXS_COUNT_CACHE_PERIOD - BLOCKSCOUT_CONTAINER_PARAMS += -e 'TXS_COUNT_CACHE_PERIOD=$(TXS_COUNT_CACHE_PERIOD)' +ifdef CACHE_TXS_COUNT_PERIOD + BLOCKSCOUT_CONTAINER_PARAMS += -e 'CACHE_TXS_COUNT_PERIOD=$(CACHE_TXS_COUNT_PERIOD)' endif -ifdef ADDRESS_WITH_BALANCES_UPDATE_INTERVAL - BLOCKSCOUT_CONTAINER_PARAMS += -e 'ADDRESS_WITH_BALANCES_UPDATE_INTERVAL=$(ADDRESS_WITH_BALANCES_UPDATE_INTERVAL)' +ifdef CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL + BLOCKSCOUT_CONTAINER_PARAMS += -e 'CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL=$(CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL)' endif ifdef LINK_TO_OTHER_EXPLORERS BLOCKSCOUT_CONTAINER_PARAMS += -e 'LINK_TO_OTHER_EXPLORERS=$(LINK_TO_OTHER_EXPLORERS)' @@ -145,14 +145,14 @@ endif ifdef SUPPORTED_CHAINS BLOCKSCOUT_CONTAINER_PARAMS += -e 'SUPPORTED_CHAINS=$(SUPPORTED_CHAINS)' endif -ifdef BLOCK_COUNT_CACHE_PERIOD - BLOCKSCOUT_CONTAINER_PARAMS += -e 'BLOCK_COUNT_CACHE_PERIOD=$(BLOCK_COUNT_CACHE_PERIOD)' +ifdef CACHE_BLOCK_COUNT_PERIOD + BLOCKSCOUT_CONTAINER_PARAMS += -e 'CACHE_BLOCK_COUNT_PERIOD=$(CACHE_BLOCK_COUNT_PERIOD)' endif -ifdef ADDRESS_SUM_CACHE_PERIOD - BLOCKSCOUT_CONTAINER_PARAMS += -e 'ADDRESS_SUM_CACHE_PERIOD=$(ADDRESS_SUM_CACHE_PERIOD)' +ifdef CACHE_ADDRESS_SUM_PERIOD + BLOCKSCOUT_CONTAINER_PARAMS += -e 'CACHE_ADDRESS_SUM_PERIOD=$(CACHE_ADDRESS_SUM_PERIOD)' endif -ifdef ADDRESS_COUNT_CACHE_PERIOD - BLOCKSCOUT_CONTAINER_PARAMS += -e 'ADDRESS_COUNT_CACHE_PERIOD=$(ADDRESS_COUNT_CACHE_PERIOD)' +ifdef CACHE_ADDRESS_COUNT_PERIOD + BLOCKSCOUT_CONTAINER_PARAMS += -e 'CACHE_ADDRESS_COUNT_PERIOD=$(CACHE_ADDRESS_COUNT_PERIOD)' endif ifdef ALLOWED_EVM_VERSIONS BLOCKSCOUT_CONTAINER_PARAMS += -e 'ALLOWED_EVM_VERSIONS=$(ALLOWED_EVM_VERSIONS)' @@ -160,11 +160,11 @@ endif ifdef UNCLES_IN_AVERAGE_BLOCK_TIME BLOCKSCOUT_CONTAINER_PARAMS += -e 'UNCLES_IN_AVERAGE_BLOCK_TIME=$(UNCLES_IN_AVERAGE_BLOCK_TIME)' endif -ifdef AVERAGE_BLOCK_CACHE_PERIOD - BLOCKSCOUT_CONTAINER_PARAMS += -e 'AVERAGE_BLOCK_CACHE_PERIOD=$(AVERAGE_BLOCK_CACHE_PERIOD)' +ifdef CACHE_AVERAGE_BLOCK_PERIOD + BLOCKSCOUT_CONTAINER_PARAMS += -e 'CACHE_AVERAGE_BLOCK_PERIOD=$(CACHE_AVERAGE_BLOCK_PERIOD)' endif -ifdef MARKET_HISTORY_CACHE_PERIOD - BLOCKSCOUT_CONTAINER_PARAMS += -e 'MARKET_HISTORY_CACHE_PERIOD=$(MARKET_HISTORY_CACHE_PERIOD)' +ifdef CACHE_MARKET_HISTORY_PERIOD + BLOCKSCOUT_CONTAINER_PARAMS += -e 'CACHE_MARKET_HISTORY_PERIOD=$(CACHE_MARKET_HISTORY_PERIOD)' endif ifdef DISABLE_WEBAPP BLOCKSCOUT_CONTAINER_PARAMS += -e 'DISABLE_WEBAPP=$(DISABLE_WEBAPP)' @@ -262,8 +262,8 @@ endif ifdef FOREIGN_JSON_RPC BLOCKSCOUT_CONTAINER_PARAMS += -e 'FOREIGN_JSON_RPC=$(FOREIGN_JSON_RPC)' endif -ifdef BRIDGE_MARKET_CAP_UPDATE_INTERVAL - BLOCKSCOUT_CONTAINER_PARAMS += -e 'BRIDGE_MARKET_CAP_UPDATE_INTERVAL=$(BRIDGE_MARKET_CAP_UPDATE_INTERVAL)' +ifdef CACHE_BRIDGE_MARKET_CAP_UPDATE_INTERVAL + BLOCKSCOUT_CONTAINER_PARAMS += -e 'CACHE_BRIDGE_MARKET_CAP_UPDATE_INTERVAL=$(CACHE_BRIDGE_MARKET_CAP_UPDATE_INTERVAL)' endif ifdef RESTRICTED_LIST BLOCKSCOUT_CONTAINER_PARAMS += -e 'RESTRICTED_LIST=$(RESTRICTED_LIST)' @@ -271,18 +271,20 @@ endif ifdef RESTRICTED_LIST_KEY BLOCKSCOUT_CONTAINER_PARAMS += -e 'RESTRICTED_LIST_KEY=$(RESTRICTED_LIST_KEY)' endif -ifdef ADDRESS_TRANSACTIONS_CACHE_PERIOD - BLOCKSCOUT_CONTAINER_PARAMS += -e 'ADDRESS_TRANSACTIONS_CACHE_PERIOD=$(ADDRESS_TRANSACTIONS_CACHE_PERIOD)' +ifdef CACHE_ADDRESS_TRANSACTIONS_PERIOD + BLOCKSCOUT_CONTAINER_PARAMS += -e 'CACHE_ADDRESS_TRANSACTIONS_PERIOD=$(CACHE_ADDRESS_TRANSACTIONS_PERIOD)' endif ifdef DISABLE_BRIDGE_MARKET_CAP_UPDATER BLOCKSCOUT_CONTAINER_PARAMS += -e 'DISABLE_BRIDGE_MARKET_CAP_UPDATER=$(DISABLE_BRIDGE_MARKET_CAP_UPDATER)' endif - -ifdef ADDRESS_TRANSACTIONS_GAS_USAGE_COUNTER_CACHE_PERIOD - BLOCKSCOUT_CONTAINER_PARAMS += -e 'ADDRESS_TRANSACTIONS_GAS_USAGE_COUNTER_CACHE_PERIOD=$(ADDRESS_TRANSACTIONS_GAS_USAGE_COUNTER_CACHE_PERIOD)' +ifdef CACHE_ADDRESS_TRANSACTIONS_GAS_USAGE_COUNTER_PERIOD + BLOCKSCOUT_CONTAINER_PARAMS += -e 'CACHE_ADDRESS_TRANSACTIONS_GAS_USAGE_COUNTER_PERIOD=$(CACHE_ADDRESS_TRANSACTIONS_GAS_USAGE_COUNTER_PERIOD)' +endif +ifdef CACHE_TOTAL_GAS_USAGE_PERIOD + BLOCKSCOUT_CONTAINER_PARAMS += -e 'CACHE_TOTAL_GAS_USAGE_PERIOD=$(CACHE_TOTAL_GAS_USAGE_PERIOD)' endif -ifdef TOTAL_GAS_USAGE_CACHE_PERIOD - BLOCKSCOUT_CONTAINER_PARAMS += -e 'TOTAL_GAS_USAGE_CACHE_PERIOD=$(TOTAL_GAS_USAGE_CACHE_PERIOD)' +ifdef CACHE_ENABLE_TOTAL_GAS_USAGE_COUNTER + BLOCKSCOUT_CONTAINER_PARAMS += -e 'CACHE_ENABLE_TOTAL_GAS_USAGE_COUNTER=$(CACHE_ENABLE_TOTAL_GAS_USAGE_COUNTER)' endif ifdef DISABLE_KNOWN_TOKENS BLOCKSCOUT_CONTAINER_PARAMS += -e 'DISABLE_KNOWN_TOKENS=$(DISABLE_KNOWN_TOKENS)' @@ -305,11 +307,11 @@ endif ifdef ENABLE_POS_STAKING_IN_MENU BLOCKSCOUT_CONTAINER_PARAMS += -e 'ENABLE_POS_STAKING_IN_MENU=$(ENABLE_POS_STAKING_IN_MENU)' endif -ifdef TOKEN_EXCHANGE_RATE_CACHE_PERIOD - BLOCKSCOUT_CONTAINER_PARAMS += -e 'TOKEN_EXCHANGE_RATE_CACHE_PERIOD=$(TOKEN_EXCHANGE_RATE_CACHE_PERIOD)' +ifdef CACHE_TOKEN_EXCHANGE_RATE_PERIOD + BLOCKSCOUT_CONTAINER_PARAMS += -e 'CACHE_TOKEN_EXCHANGE_RATE_PERIOD=$(CACHE_TOKEN_EXCHANGE_RATE_PERIOD)' endif -ifdef ADDRESS_TOKENS_USD_SUM_CACHE_PERIOD - BLOCKSCOUT_CONTAINER_PARAMS += -e 'ADDRESS_TOKENS_USD_SUM_CACHE_PERIOD=$(ADDRESS_TOKENS_USD_SUM_CACHE_PERIOD)' +ifdef CACHE_ADDRESS_TOKENS_USD_SUM_PERIOD + BLOCKSCOUT_CONTAINER_PARAMS += -e 'CACHE_ADDRESS_TOKENS_USD_SUM_PERIOD=$(CACHE_ADDRESS_TOKENS_USD_SUM_PERIOD)' endif ifdef SHOW_MAINTENANCE_ALERT BLOCKSCOUT_CONTAINER_PARAMS += -e 'SHOW_MAINTENANCE_ALERT=$(SHOW_MAINTENANCE_ALERT)' @@ -359,8 +361,8 @@ endif ifdef RE_CAPTCHA_CLIENT_KEY BLOCKSCOUT_CONTAINER_PARAMS += -e 'RE_CAPTCHA_CLIENT_KEY=$(RE_CAPTCHA_CLIENT_KEY)' endif -ifdef ADDRESS_TOKEN_TRANSFERS_COUNTER_CACHE_PERIOD - BLOCKSCOUT_CONTAINER_PARAMS += -e 'ADDRESS_TOKEN_TRANSFERS_COUNTER_CACHE_PERIOD=$(ADDRESS_TOKEN_TRANSFERS_COUNTER_CACHE_PERIOD)' +ifdef CACHE_ADDRESS_TOKEN_TRANSFERS_COUNTER_PERIOD + BLOCKSCOUT_CONTAINER_PARAMS += -e 'CACHE_ADDRESS_TOKEN_TRANSFERS_COUNTER_PERIOD=$(CACHE_ADDRESS_TOKEN_TRANSFERS_COUNTER_PERIOD)' endif ifdef API_RATE_LIMIT BLOCKSCOUT_CONTAINER_PARAMS += -e 'API_RATE_LIMIT=$(API_RATE_LIMIT)' From 19a7f4fa500ca5039183a772c8be6cbeddedebf4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 9 Apr 2022 00:07:46 +0000 Subject: [PATCH 044/128] Bump moment from 2.29.1 to 2.29.2 in /apps/block_scout_web/assets Bumps [moment](https://github.com/moment/moment) from 2.29.1 to 2.29.2. - [Release notes](https://github.com/moment/moment/releases) - [Changelog](https://github.com/moment/moment/blob/develop/CHANGELOG.md) - [Commits](https://github.com/moment/moment/compare/2.29.1...2.29.2) --- updated-dependencies: - dependency-name: moment dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- apps/block_scout_web/assets/package-lock.json | 19 +++++++++---------- apps/block_scout_web/assets/package.json | 2 +- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/apps/block_scout_web/assets/package-lock.json b/apps/block_scout_web/assets/package-lock.json index 8b7b50d44b4a..87526f331bb1 100644 --- a/apps/block_scout_web/assets/package-lock.json +++ b/apps/block_scout_web/assets/package-lock.json @@ -43,7 +43,7 @@ "lodash.rangeright": "^4.2.0", "lodash.reduce": "^4.6.0", "luxon": "^2.3.0", - "moment": "^2.29.1", + "moment": "^2.29.2", "nanomorph": "^5.4.0", "numeral": "^2.0.6", "os-browserify": "^0.3.0", @@ -95,11 +95,10 @@ } }, "../../../deps/phoenix": { - "version": "1.5.13", - "license": "MIT" + "version": "0.0.1" }, "../../../deps/phoenix_html": { - "version": "2.14.3" + "version": "0.0.1" }, "node_modules/@babel/code-frame": { "version": "7.16.7", @@ -12853,9 +12852,9 @@ "integrity": "sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw==" }, "node_modules/moment": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", - "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==", + "version": "2.29.2", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.2.tgz", + "integrity": "sha512-UgzG4rvxYpN15jgCmVJwac49h9ly9NurikMWGPdVxm8GZD6XjkKPxDTjQQ43gtGgnV3X0cAyWDdP2Wexoquifg==", "engines": { "node": "*" } @@ -28060,9 +28059,9 @@ "integrity": "sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw==" }, "moment": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", - "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" + "version": "2.29.2", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.2.tgz", + "integrity": "sha512-UgzG4rvxYpN15jgCmVJwac49h9ly9NurikMWGPdVxm8GZD6XjkKPxDTjQQ43gtGgnV3X0cAyWDdP2Wexoquifg==" }, "ms": { "version": "2.1.2", diff --git a/apps/block_scout_web/assets/package.json b/apps/block_scout_web/assets/package.json index 744b94cce125..9e4864a69925 100644 --- a/apps/block_scout_web/assets/package.json +++ b/apps/block_scout_web/assets/package.json @@ -55,7 +55,7 @@ "lodash.rangeright": "^4.2.0", "lodash.reduce": "^4.6.0", "luxon": "^2.3.0", - "moment": "^2.29.1", + "moment": "^2.29.2", "nanomorph": "^5.4.0", "numeral": "^2.0.6", "os-browserify": "^0.3.0", From e1a49f3449d712e5a4df93a395a6630533c9500e Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Mon, 11 Apr 2022 15:56:50 +0300 Subject: [PATCH 045/128] Geth: display tx revert reason --- .dialyzer-ignore | 1 - CHANGELOG.md | 1 + .../controllers/api/rpc/transaction_controller.ex | 8 ++------ .../templates/transaction/overview.html.eex | 2 +- apps/explorer/lib/explorer/chain.ex | 13 +++++++++++-- apps/explorer/lib/explorer/chain/gas.ex | 2 +- 6 files changed, 16 insertions(+), 11 deletions(-) diff --git a/.dialyzer-ignore b/.dialyzer-ignore index e3385f7b4ae0..ec75e5e7ddb8 100644 --- a/.dialyzer-ignore +++ b/.dialyzer-ignore @@ -18,7 +18,6 @@ lib/phoenix/router.ex:324 lib/phoenix/router.ex:402 lib/block_scout_web/views/layout_view.ex:145: The call 'Elixir.Poison.Parser':'parse!' lib/block_scout_web/views/layout_view.ex:237: The call 'Elixir.Poison.Parser':'parse!' -lib/block_scout_web/controllers/api/rpc/transaction_controller.ex:22 lib/explorer/smart_contract/reader.ex:435 lib/indexer/fetcher/token_total_supply_on_demand.ex:16 lib/explorer/exchange_rates/source.ex:110 diff --git a/CHANGELOG.md b/CHANGELOG.md index 327e87ade4de..9bd408bf2138 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - [#5268](https://github.com/blockscout/blockscout/pull/5268) - Contract names display improvement ### Fixes +- [#5443](https://github.com/blockscout/blockscout/pull/5443) - Geth: display tx revert reason - [#5416](https://github.com/blockscout/blockscout/pull/5416) - Fix getsourcecode for EOA addresses - [#5411](https://github.com/blockscout/blockscout/pull/5411) - Fix character_not_in_repertoire error for tx revert reason - [#5410](https://github.com/blockscout/blockscout/pull/5410) - Handle exited realtime fetcher diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/transaction_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/transaction_controller.ex index 0242d37acb4c..8cf1e556199a 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/transaction_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/transaction_controller.ex @@ -17,12 +17,8 @@ defmodule BlockScoutWeb.API.RPC.TransactionController do {logs, next_page} = split_list_by_page(logs) transaction_updated = - if error == "Reverted" do - if revert_reason == nil do - %Transaction{transaction | revert_reason: Chain.fetch_tx_revert_reason(transaction)} - else - transaction - end + if (error == "Reverted" || error == "execution reverted") && !revert_reason do + %Transaction{transaction | revert_reason: Chain.fetch_tx_revert_reason(transaction)} else transaction end diff --git a/apps/block_scout_web/lib/block_scout_web/templates/transaction/overview.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/transaction/overview.html.eex index de9e94714e79..b67ec92f486c 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/transaction/overview.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/transaction/overview.html.eex @@ -121,7 +121,7 @@ - <%= if status == {:error, "Reverted"} do %> + <%= if status == {:error, "Reverted"} || status == {:error, "execution reverted"} do %>
<%= render BlockScoutWeb.CommonComponentsView, "_i_tooltip_2.html", diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index 3661350a9c63..3f25f63e99ae 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -93,6 +93,8 @@ defmodule Explorer.Chain do @revert_msg_prefix_2 "revert: " @revert_msg_prefix_3 "reverted " @revert_msg_prefix_4 "Reverted " + # Geth-like node + @revert_msg_prefix_5 "execution reverted: " # keccak256("Error(string)") @revert_error_method_id "08c379a0" @@ -3655,16 +3657,20 @@ defmodule Explorer.Chain do Wei.hex_format(value) ) - data = + revert_reason = case EthereumJSONRPC.json_rpc(req, json_rpc_named_arguments) do {:error, %{data: data}} -> data + {:error, %{message: message}} -> + message + _ -> "" end - formatted_revert_reason = data |> format_revert_reason_message() |> (&if(String.valid?(&1), do: &1, else: data)).() + formatted_revert_reason = + revert_reason |> format_revert_reason_message() |> (&if(String.valid?(&1), do: &1, else: revert_reason)).() if byte_size(formatted_revert_reason) > 0 do transaction @@ -3689,6 +3695,9 @@ defmodule Explorer.Chain do @revert_msg_prefix_4 <> rest -> extract_revert_reason_message_wrapper(rest) + @revert_msg_prefix_5 <> rest -> + extract_revert_reason_message_wrapper(rest) + revert_reason_full -> revert_reason_full end diff --git a/apps/explorer/lib/explorer/chain/gas.ex b/apps/explorer/lib/explorer/chain/gas.ex index 381a1ab3fbad..06eae13e1a14 100644 --- a/apps/explorer/lib/explorer/chain/gas.ex +++ b/apps/explorer/lib/explorer/chain/gas.ex @@ -6,5 +6,5 @@ defmodule Explorer.Chain.Gas do """ @typedoc @moduledoc - @type t :: non_neg_integer() + @type t :: false | nil | %Decimal{:coef => non_neg_integer(), :exp => integer(), :sign => -1 | 1} end From e1541db6d6dd009e9743af3f84905582ddd8bd67 Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Tue, 12 Apr 2022 15:18:37 +0300 Subject: [PATCH 046/128] Logging error in publishing of smart-contract --- CHANGELOG.md | 1 + .../api/rpc/contract_controller.ex | 47 ++++++++++++------- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bd408bf2138..c4de62255400 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ - [#5239](https://github.com/blockscout/blockscout/pull/5239) - Add accounting for block rewards in `getblockreward` api method ### Chore +- [#5450](https://github.com/blockscout/blockscout/pull/5450) - Logging error in publishing of smart-contract - [#5433](https://github.com/blockscout/blockscout/pull/5433) - Caching modules refactoring - [#5419](https://github.com/blockscout/blockscout/pull/5419) - Add check if address exists for some api methods - [#5408](https://github.com/blockscout/blockscout/pull/5408) - Update websocket_client hex package diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/contract_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/contract_controller.ex index 83676fa5551f..ae289a38a256 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/contract_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/contract_controller.ex @@ -1,6 +1,8 @@ defmodule BlockScoutWeb.API.RPC.ContractController do use BlockScoutWeb, :controller + require Logger + alias BlockScoutWeb.AddressContractVerificationController, as: VerificationController alias BlockScoutWeb.API.RPC.Helpers alias Explorer.Chain @@ -13,6 +15,12 @@ defmodule BlockScoutWeb.API.RPC.ContractController do alias Explorer.SmartContract.Vyper.Publisher, as: VyperPublisher alias Explorer.ThirdPartyIntegrations.Sourcify + @smth_went_wrong "Something went wrong while publishing the contract." + @verified "Smart-contract already verified." + @invalid_address "Invalid address hash" + @invalid_args "Invalid args format" + @address_required "Query parameter address is required" + def verify(conn, %{"addressHash" => address_hash} = params) do with {:params, {:ok, fetched_params}} <- {:params, fetch_verify_params(params)}, {:format, {:ok, casted_address_hash}} <- to_address_hash(address_hash), @@ -36,13 +44,20 @@ defmodule BlockScoutWeb.API.RPC.ContractController do ]} ] }}} -> - render(conn, :error, error: "Smart-contract already verified.") + render(conn, :error, error: @verified) - {:publish, _} -> - render(conn, :error, error: "Something went wrong while publishing the contract.") + {:publish, error} -> + Logger.error(fn -> + [ + @smth_went_wrong, + inspect(error) + ] + end) + + render(conn, :error, error: @smth_went_wrong) {:format, :error} -> - render(conn, :error, error: "Invalid address hash") + render(conn, :error, error: @invalid_address) {:params, {:error, error}} -> render(conn, :error, error: error) @@ -58,7 +73,7 @@ defmodule BlockScoutWeb.API.RPC.ContractController do end if Chain.smart_contract_fully_verified?(address_hash) do - render(conn, :error, error: "Smart-contract already verified.") + render(conn, :error, error: @verified) else case Sourcify.check_by_address(address_hash) do {:ok, _verified_status} -> @@ -97,10 +112,10 @@ defmodule BlockScoutWeb.API.RPC.ContractController do render(conn, :show, %{result: uid}) else {:check_verified_status, true} -> - render(conn, :error, error: "Smart-contract already verified.", data: "Smart-contract already verified") + render(conn, :error, error: @verified, data: @verified) {:format, :error} -> - render(conn, :error, error: "Invalid address hash", data: "Invalid address hash") + render(conn, :error, error: @invalid_address, data: @invalid_address) {:params, {:error, error}} -> render(conn, :error, error: error, data: error) @@ -128,7 +143,7 @@ defmodule BlockScoutWeb.API.RPC.ContractController do end defp prepare_params(files) when is_struct(files) do - {:error, "Invalid args format"} + {:error, @invalid_args} end defp prepare_params(files) when is_map(files) do @@ -140,7 +155,7 @@ defmodule BlockScoutWeb.API.RPC.ContractController do end defp prepare_params(_arg) do - {:error, "Invalid args format"} + {:error, @invalid_args} end defp validate_files(files) do @@ -269,13 +284,13 @@ defmodule BlockScoutWeb.API.RPC.ContractController do ]} ] }}} -> - render(conn, :error, error: "Smart-contract already verified.") + render(conn, :error, error: @verified) {:publish, _} -> - render(conn, :error, error: "Something went wrong while publishing the contract.") + render(conn, :error, error: @smth_went_wrong) {:format, :error} -> - render(conn, :error, error: "Invalid address hash") + render(conn, :error, error: @invalid_address) {:params, {:error, error}} -> render(conn, :error, error: error) @@ -357,10 +372,10 @@ defmodule BlockScoutWeb.API.RPC.ContractController do render(conn, :getabi, %{abi: contract.abi}) else {:address_param, :error} -> - render(conn, :error, error: "Query parameter address is required") + render(conn, :error, error: @address_required) {:format, :error} -> - render(conn, :error, error: "Invalid address hash") + render(conn, :error, error: @invalid_address) {:contract, :not_found} -> render(conn, :error, error: "Contract source code not verified") @@ -378,10 +393,10 @@ defmodule BlockScoutWeb.API.RPC.ContractController do }) else {:address_param, :error} -> - render(conn, :error, error: "Query parameter address is required") + render(conn, :error, error: @address_required) {:format, :error} -> - render(conn, :error, error: "Invalid address hash") + render(conn, :error, error: @invalid_address) {:contract, :not_found} -> render(conn, :getsourcecode, %{contract: nil, address_hash: nil}) From b845a81983e24ae775e90b294e2d3033c78206de Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Apr 2022 00:16:07 +0000 Subject: [PATCH 047/128] Bump urijs from 1.19.10 to 1.19.11 in /apps/block_scout_web/assets Bumps [urijs](https://github.com/medialize/URI.js) from 1.19.10 to 1.19.11. - [Release notes](https://github.com/medialize/URI.js/releases) - [Changelog](https://github.com/medialize/URI.js/blob/gh-pages/CHANGELOG.md) - [Commits](https://github.com/medialize/URI.js/compare/v1.19.10...v1.19.11) --- updated-dependencies: - dependency-name: urijs dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- apps/block_scout_web/assets/package-lock.json | 14 +++++++------- apps/block_scout_web/assets/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/block_scout_web/assets/package-lock.json b/apps/block_scout_web/assets/package-lock.json index 87526f331bb1..2512c4aac119 100644 --- a/apps/block_scout_web/assets/package-lock.json +++ b/apps/block_scout_web/assets/package-lock.json @@ -57,7 +57,7 @@ "stream-browserify": "^3.0.0", "stream-http": "^3.1.1", "sweetalert2": "^11.3.10", - "urijs": "^1.19.2", + "urijs": "^1.19.11", "url": "^0.11.0", "util": "^0.12.3", "web3": "^1.7.0", @@ -17019,9 +17019,9 @@ } }, "node_modules/urijs": { - "version": "1.19.10", - "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.10.tgz", - "integrity": "sha512-EzauQlgKuJgsXOqoMrCiePBf4At5jVqRhXykF3Wfb8ZsOBMxPcfiVBcsHXug4Aepb/ICm2PIgqAUGMelgdrWEg==" + "version": "1.19.11", + "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz", + "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==" }, "node_modules/url": { "version": "0.11.0", @@ -31185,9 +31185,9 @@ } }, "urijs": { - "version": "1.19.10", - "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.10.tgz", - "integrity": "sha512-EzauQlgKuJgsXOqoMrCiePBf4At5jVqRhXykF3Wfb8ZsOBMxPcfiVBcsHXug4Aepb/ICm2PIgqAUGMelgdrWEg==" + "version": "1.19.11", + "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz", + "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==" }, "url": { "version": "0.11.0", diff --git a/apps/block_scout_web/assets/package.json b/apps/block_scout_web/assets/package.json index 9e4864a69925..c0c1d14c8113 100644 --- a/apps/block_scout_web/assets/package.json +++ b/apps/block_scout_web/assets/package.json @@ -69,7 +69,7 @@ "stream-browserify": "^3.0.0", "stream-http": "^3.1.1", "sweetalert2": "^11.3.10", - "urijs": "^1.19.2", + "urijs": "^1.19.11", "url": "^0.11.0", "util": "^0.12.3", "web3": "^1.7.0", From 7b832bf8d14c02c3a264a2e92e208d614cfef860 Mon Sep 17 00:00:00 2001 From: Ryan Wang Date: Tue, 12 Apr 2022 21:51:46 -0700 Subject: [PATCH 048/128] changed to update qemu-x86_64 for alpine to fix the signal 11 error. --- docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 5378f1f27fdb..82a6de93ae40 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,6 +1,6 @@ FROM bitwalker/alpine-elixir-phoenix:1.13 -RUN apk --no-cache --update add alpine-sdk gmp-dev automake libtool inotify-tools autoconf python3 file +RUN apk --no-cache --update add alpine-sdk gmp-dev automake libtool inotify-tools autoconf python3 file qemu-x86_64 ENV GLIBC_REPO=https://github.com/sgerrand/alpine-pkg-glibc ENV GLIBC_VERSION=2.30-r0 From 163c8ff8c9bcf0bc632f44acfb0340b6fae2dac3 Mon Sep 17 00:00:00 2001 From: Ryan Wang Date: Tue, 12 Apr 2022 22:21:55 -0700 Subject: [PATCH 049/128] updated the changelog. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c4de62255400..c25051478f08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - [#5268](https://github.com/blockscout/blockscout/pull/5268) - Contract names display improvement ### Fixes +- [#5454](https://github.com/blockscout/blockscout/pull/5454) - Docker: Fix the qemu-x86_64 signal 11 error on Apple Silicon - [#5443](https://github.com/blockscout/blockscout/pull/5443) - Geth: display tx revert reason - [#5416](https://github.com/blockscout/blockscout/pull/5416) - Fix getsourcecode for EOA addresses - [#5411](https://github.com/blockscout/blockscout/pull/5411) - Fix character_not_in_repertoire error for tx revert reason From 3cb6de8540b7501184a76b5aa24faccd69c5ac4b Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Wed, 13 Apr 2022 11:01:40 +0300 Subject: [PATCH 050/128] Fix unverified_smart_contract function: add md5 of bytecode to the changeset --- CHANGELOG.md | 1 + .../controllers/api/rpc/contract_controller.ex | 14 +++++++++++++- .../explorer/smart_contract/solidity/publisher.ex | 7 +++++-- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c4de62255400..64c327ff14ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - [#5268](https://github.com/blockscout/blockscout/pull/5268) - Contract names display improvement ### Fixes +- [#5455](https://github.com/blockscout/blockscout/pull/5455) - Fix unverified_smart_contract function: add md5 of bytecode to the changeset - [#5443](https://github.com/blockscout/blockscout/pull/5443) - Geth: display tx revert reason - [#5416](https://github.com/blockscout/blockscout/pull/5416) - Fix getsourcecode for EOA addresses - [#5411](https://github.com/blockscout/blockscout/pull/5411) - Fix character_not_in_repertoire error for tx revert reason diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/contract_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/contract_controller.ex index ae289a38a256..5ab78945a607 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/contract_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/contract_controller.ex @@ -15,7 +15,7 @@ defmodule BlockScoutWeb.API.RPC.ContractController do alias Explorer.SmartContract.Vyper.Publisher, as: VyperPublisher alias Explorer.ThirdPartyIntegrations.Sourcify - @smth_went_wrong "Something went wrong while publishing the contract." + @smth_went_wrong "Something went wrong while publishing the contract" @verified "Smart-contract already verified." @invalid_address "Invalid address hash" @invalid_args "Invalid args format" @@ -46,10 +46,22 @@ defmodule BlockScoutWeb.API.RPC.ContractController do }}} -> render(conn, :error, error: @verified) + {:publish, {:error, error}} -> + Logger.error(fn -> + [ + @smth_went_wrong, + ": ", + inspect(error) + ] + end) + + render(conn, :error, error: "#{@smth_went_wrong}: #{inspect(error.errors)}") + {:publish, error} -> Logger.error(fn -> [ @smth_went_wrong, + ": ", inspect(error) ] end) diff --git a/apps/explorer/lib/explorer/smart_contract/solidity/publisher.ex b/apps/explorer/lib/explorer/smart_contract/solidity/publisher.ex index e947461b115b..7c55ead66351 100644 --- a/apps/explorer/lib/explorer/smart_contract/solidity/publisher.ex +++ b/apps/explorer/lib/explorer/smart_contract/solidity/publisher.ex @@ -5,7 +5,7 @@ defmodule Explorer.SmartContract.Solidity.Publisher do alias Explorer.Chain alias Explorer.Chain.SmartContract - alias Explorer.SmartContract.CompilerVersion + alias Explorer.SmartContract.{CompilerVersion, Helper} alias Explorer.SmartContract.Solidity.Verifier @doc """ @@ -91,7 +91,10 @@ defmodule Explorer.SmartContract.Solidity.Publisher do end defp unverified_smart_contract(address_hash, params, error, error_message, json_verification \\ false) do - attrs = attributes(address_hash, params) + attrs = + address_hash + |> attributes(params) + |> Helper.add_contract_code_md5() changeset = SmartContract.invalid_contract_changeset( From f2d4fa6412decce8cccbb8386e18249b428f36cc Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Wed, 13 Apr 2022 16:24:27 +0300 Subject: [PATCH 051/128] Ignore arbitrary block details fields for custom Ethereum clients --- CHANGELOG.md | 1 + .../lib/ethereum_jsonrpc/block.ex | 16 +++++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 64c327ff14ef..6fd4549adf2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ - [#5239](https://github.com/blockscout/blockscout/pull/5239) - Add accounting for block rewards in `getblockreward` api method ### Chore +- [#5456](https://github.com/blockscout/blockscout/pull/5456) - Ignore arbitrary block details fields for custom Ethereum clients - [#5450](https://github.com/blockscout/blockscout/pull/5450) - Logging error in publishing of smart-contract - [#5433](https://github.com/blockscout/blockscout/pull/5433) - Caching modules refactoring - [#5419](https://github.com/blockscout/blockscout/pull/5419) - Add check if address exists for some api methods diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/block.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/block.ex index f36c5cc742ce..7c4de364b95c 100644 --- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/block.ex +++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/block.ex @@ -585,13 +585,9 @@ defmodule EthereumJSONRPC.Block do # double check that no new keys are being missed by requiring explicit match for passthrough # `t:EthereumJSONRPC.address/0` and `t:EthereumJSONRPC.hash/0` pass through as `Explorer.Chain` can verify correct # hash format - # bitcoinMergedMiningCoinbaseTransaction bitcoinMergedMiningHeader bitcoinMergedMiningMerkleProof hashForMergedMining - RSK https://github.com/blockscout/blockscout/pull/2934 - # committedSeals committee pastCommittedSeals proposerSeal round - Autonity network https://github.com/blockscout/blockscout/pull/3480 - # blockGasCost extDataGasUsed - sgb/ava https://github.com/blockscout/blockscout/pull/5301 - # blockExtraData extDataHash - Avalanche https://github.com/blockscout/blockscout/pull/5348 defp entry_to_elixir({key, _} = entry) when key in ~w(author extraData hash logsBloom miner mixHash nonce parentHash receiptsRoot sealFields sha3Uncles - signature stateRoot step transactionsRoot uncles bitcoinMergedMiningCoinbaseTransaction bitcoinMergedMiningHeader bitcoinMergedMiningMerkleProof hashForMergedMining committedSeals committee pastCommittedSeals proposerSeal round blockGasCost extDataGasUsed blockExtraData extDataHash), + signature stateRoot step transactionsRoot uncles), do: entry defp entry_to_elixir({"timestamp" = key, timestamp}) do @@ -606,4 +602,14 @@ defmodule EthereumJSONRPC.Block do defp entry_to_elixir({"l1BlockNumber", _}) do {:ignore, :ignore} end + + # bitcoinMergedMiningCoinbaseTransaction bitcoinMergedMiningHeader bitcoinMergedMiningMerkleProof hashForMergedMining - RSK https://github.com/blockscout/blockscout/pull/2934 + # committedSeals committee pastCommittedSeals proposerSeal round - Autonity network https://github.com/blockscout/blockscout/pull/3480 + # blockGasCost extDataGasUsed - sgb/ava https://github.com/blockscout/blockscout/pull/5301 + # blockExtraData extDataHash - Avalanche https://github.com/blockscout/blockscout/pull/5348 + # vrf vrfProof - Harmony + # ... + defp entry_to_elixir({_, _}) do + {:ignore, :ignore} + end end From 93909e28d31f890a07eeb6743fae95ff54469b77 Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Wed, 13 Apr 2022 18:42:43 +0300 Subject: [PATCH 052/128] Decrease min safe polling period for realtime fetcher --- CHANGELOG.md | 1 + apps/explorer/lib/explorer/counters/average_block_time.ex | 2 +- apps/indexer/lib/indexer/block/realtime/fetcher.ex | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6fd4549adf2d..9605fda25135 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ - [#5239](https://github.com/blockscout/blockscout/pull/5239) - Add accounting for block rewards in `getblockreward` api method ### Chore +- [#5458](https://github.com/blockscout/blockscout/pull/5458) - Decrease min safe polling period for realtime fetcher - [#5456](https://github.com/blockscout/blockscout/pull/5456) - Ignore arbitrary block details fields for custom Ethereum clients - [#5450](https://github.com/blockscout/blockscout/pull/5450) - Logging error in publishing of smart-contract - [#5433](https://github.com/blockscout/blockscout/pull/5433) - Caching modules refactoring diff --git a/apps/explorer/lib/explorer/counters/average_block_time.ex b/apps/explorer/lib/explorer/counters/average_block_time.ex index 81142283d887..2c575a5fac9a 100644 --- a/apps/explorer/lib/explorer/counters/average_block_time.ex +++ b/apps/explorer/lib/explorer/counters/average_block_time.ex @@ -130,7 +130,7 @@ defmodule Explorer.Counters.AverageBlockTime do end defp average_block_cache_period do - case Integer.parse(System.get_env("CACE_AVERAGE_BLOCK_PERIOD", "")) do + case Integer.parse(System.get_env("CACHE_AVERAGE_BLOCK_PERIOD", "")) do {secs, ""} -> :timer.seconds(secs) _ -> :timer.minutes(30) end diff --git a/apps/indexer/lib/indexer/block/realtime/fetcher.ex b/apps/indexer/lib/indexer/block/realtime/fetcher.ex index 4529a7613429..8dcba66f57d5 100644 --- a/apps/indexer/lib/indexer/block/realtime/fetcher.ex +++ b/apps/indexer/lib/indexer/block/realtime/fetcher.ex @@ -37,7 +37,7 @@ defmodule Indexer.Block.Realtime.Fetcher do @behaviour Block.Fetcher - @minimum_safe_polling_period :timer.seconds(5) + @minimum_safe_polling_period :timer.seconds(1) @enforce_keys ~w(block_fetcher)a defstruct ~w(block_fetcher subscription previous_number max_number_seen timer)a From 81338d48c8137c1ed6a8dc3dc631af8b13bfeed6 Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Thu, 14 Apr 2022 13:36:30 +0300 Subject: [PATCH 053/128] Return websocket_client 1.3.0 --- apps/block_scout_web/mix.exs | 2 +- mix.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/block_scout_web/mix.exs b/apps/block_scout_web/mix.exs index 360e350fee0b..b6c8f6416fd5 100644 --- a/apps/block_scout_web/mix.exs +++ b/apps/block_scout_web/mix.exs @@ -126,7 +126,7 @@ defmodule BlockScoutWeb.Mixfile do {:timex, "~> 3.7.1"}, {:wallaby, "~> 0.28", only: :test, runtime: false}, # `:cowboy` `~> 2.0` and Phoenix 1.4 compatibility - {:websocket_client, "~> 1.4"}, + {:websocket_client, "~> 1.3"}, {:wobserver, "~> 0.2.0", github: "poanetwork/wobserver", branch: "support-https"}, {:ex_json_schema, "~> 0.6.2"} ] diff --git a/mix.lock b/mix.lock index 0a0c16a2ac9b..8e2f714ee007 100644 --- a/mix.lock +++ b/mix.lock @@ -124,6 +124,6 @@ "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, "wallaby": {:hex, :wallaby, "0.29.1", "7ad61c98a1425db291a392e45504e897b1271c746b40fe9f19f87a86729d2fac", [:mix], [{:ecto_sql, ">= 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}, {:httpoison, "~> 0.12 or ~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:phoenix_ecto, ">= 3.0.0", [hex: :phoenix_ecto, repo: "hexpm", optional: true]}, {:web_driver_client, "~> 0.2.0", [hex: :web_driver_client, repo: "hexpm", optional: false]}], "hexpm", "21b1360c4b13adbb0a1ff5c1053204cc4489ac81e9579c6c5011a27915cb7415"}, "web_driver_client": {:hex, :web_driver_client, "0.2.0", "63b76cd9eb3b0716ec5467a0f8bead73d3d9612e63f7560d21357f03ad86e31a", [:mix], [{:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:tesla, "~> 1.3", [hex: :tesla, repo: "hexpm", optional: false]}], "hexpm", "83cc6092bc3e74926d1c8455f0ce927d5d1d36707b74d9a65e38c084aab0350f"}, - "websocket_client": {:hex, :websocket_client, "1.4.2", "f1036e3f9427eecdb66808eee56dbcaeb5a1a352306e6a0d0d23a9487205f4d7", [:rebar3], [], "hexpm", "c005e5f8f2f6a8533c497a509dc52f3e6fb42fa2e0d67bff8ebc8802868d84ed"}, + "websocket_client": {:hex, :websocket_client, "1.3.0", "2275d7daaa1cdacebf2068891c9844b15f4fdc3de3ec2602420c2fb486db59b6", [:rebar3], [], "hexpm", "b864fa076f059b615da4ab99240e515b26132ce4d2d0f9df5d7f22f01fa04b65"}, "wobserver": {:git, "https://github.com/poanetwork/wobserver.git", "13bcda30a87f4f0be1878920a79433ad831eefbe", [branch: "support-https"]}, } From 175864b61794c102ca46e93d7a97c7420ce9fecf Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Mon, 18 Apr 2022 12:25:11 +0300 Subject: [PATCH 054/128] Refactor daily coin balances fetcher --- CHANGELOG.md | 1 + .../lib/indexer/block/realtime/fetcher.ex | 18 +-- .../lib/indexer/fetcher/coin_balance.ex | 105 +++++++----------- 3 files changed, 46 insertions(+), 78 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a9e21951d544..d1a4ec85b516 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ - [#5239](https://github.com/blockscout/blockscout/pull/5239) - Add accounting for block rewards in `getblockreward` api method ### Chore +- [#5473](https://github.com/blockscout/blockscout/pull/5473) - Refactor daily coin balances fetcher - [#5458](https://github.com/blockscout/blockscout/pull/5458) - Decrease min safe polling period for realtime fetcher - [#5456](https://github.com/blockscout/blockscout/pull/5456) - Ignore arbitrary block details fields for custom Ethereum clients - [#5450](https://github.com/blockscout/blockscout/pull/5450) - Logging error in publishing of smart-contract diff --git a/apps/indexer/lib/indexer/block/realtime/fetcher.ex b/apps/indexer/lib/indexer/block/realtime/fetcher.ex index 8dcba66f57d5..c0206eae2317 100644 --- a/apps/indexer/lib/indexer/block/realtime/fetcher.ex +++ b/apps/indexer/lib/indexer/block/realtime/fetcher.ex @@ -25,13 +25,14 @@ defmodule Indexer.Block.Realtime.Fetcher do ] alias Ecto.Changeset - alias EthereumJSONRPC.{Blocks, FetchedBalances, Subscription} + alias EthereumJSONRPC.{FetchedBalances, Subscription} alias Explorer.Chain alias Explorer.Chain.Cache.Accounts alias Explorer.Chain.Events.Publisher alias Explorer.Counters.AverageBlockTime alias Indexer.{Block, Tracer} alias Indexer.Block.Realtime.TaskSupervisor + alias Indexer.Fetcher.CoinBalance alias Indexer.Transform.Addresses alias Timex.Duration @@ -407,20 +408,7 @@ defmodule Indexer.Block.Realtime.Fetcher do importable_balances_params = Enum.map(params_list, &Map.put(&1, :value_fetched_at, value_fetched_at)) - block_numbers = - params_list - |> Enum.map(&Map.get(&1, :block_number)) - |> Enum.sort() - |> Enum.dedup() - - block_timestamp_map = - Enum.reduce(block_numbers, %{}, fn block_number, map -> - {:ok, %Blocks{blocks_params: [%{timestamp: timestamp}]}} = - EthereumJSONRPC.fetch_blocks_by_range(block_number..block_number, json_rpc_named_arguments) - - day = DateTime.to_date(timestamp) - Map.put(map, "#{block_number}", day) - end) + block_timestamp_map = CoinBalance.block_timestamp_map(params_list, json_rpc_named_arguments) importable_balances_daily_params = Enum.map(params_list, fn param -> diff --git a/apps/indexer/lib/indexer/fetcher/coin_balance.ex b/apps/indexer/lib/indexer/fetcher/coin_balance.ex index 94ace2f43141..7b175c7915b3 100644 --- a/apps/indexer/lib/indexer/fetcher/coin_balance.ex +++ b/apps/indexer/lib/indexer/fetcher/coin_balance.ex @@ -139,41 +139,7 @@ defmodule Indexer.Fetcher.CoinBalance do json_rpc_named_arguments = Application.get_env(:explorer, :json_rpc_named_arguments) - block_numbers = - params_list - |> Enum.map(&Map.get(&1, :block_number)) - |> Enum.sort() - |> Enum.dedup() - - block_timestamp_map = - Enum.reduce(block_numbers, %{}, fn block_number, map -> - case EthereumJSONRPC.fetch_blocks_by_range(block_number..block_number, json_rpc_named_arguments) do - {:ok, %Blocks{blocks_params: [%{timestamp: timestamp}]}} -> - day = DateTime.to_date(timestamp) - Map.put(map, "#{block_number}", day) - - _ -> - %{} - end - end) - - importable_balances_daily_params = - params_list - |> Enum.map(fn balance_param -> - if Map.has_key?(block_timestamp_map, "#{balance_param.block_number}") do - day = Map.get(block_timestamp_map, "#{balance_param.block_number}") - - incoming_balance_daily_param = %{ - address_hash: balance_param.address_hash, - day: day, - value: balance_param.value - } - - incoming_balance_daily_param - else - nil - end - end) + importable_balances_daily_params = balances_daily_params(params_list, json_rpc_named_arguments) addresses_params = balances_params_to_address_params(importable_balances_params) @@ -192,34 +158,7 @@ defmodule Indexer.Fetcher.CoinBalance do json_rpc_named_arguments = Application.get_env(:explorer, :json_rpc_named_arguments) - block_numbers = - params_list - |> Enum.map(&Map.get(&1, :block_number)) - |> Enum.sort() - |> Enum.dedup() - - block_timestamp_map = - Enum.reduce(block_numbers, %{}, fn block_number, map -> - {:ok, %Blocks{blocks_params: [%{timestamp: timestamp}]}} = - EthereumJSONRPC.fetch_blocks_by_range(block_number..block_number, json_rpc_named_arguments) - - day = DateTime.to_date(timestamp) - Map.put(map, "#{block_number}", day) - end) - - importable_balances_daily_params = - params_list - |> Enum.map(fn balance_param -> - day = Map.get(block_timestamp_map, "#{balance_param.block_number}") - - incoming_balance_daily_param = %{ - address_hash: balance_param.address_hash, - day: day, - value: balance_param.value - } - - incoming_balance_daily_param - end) + importable_balances_daily_params = balances_daily_params(params_list, json_rpc_named_arguments) addresses_params = balances_params_to_address_params(importable_balances_params) @@ -285,4 +224,44 @@ defmodule Indexer.Fetcher.CoinBalance do when is_integer(code) and is_binary(message) and is_binary(block_quantity) and is_binary(hash_data) do [hash_data, "@", quantity_to_integer(block_quantity), ": (", to_string(code), ") ", message, ?\n] end + + def block_timestamp_map(params_list, json_rpc_named_arguments) do + block_numbers = + params_list + |> Enum.map(&Map.get(&1, :block_number)) + |> Enum.sort() + |> Enum.dedup() + + Enum.reduce(block_numbers, %{}, fn block_number, map -> + case EthereumJSONRPC.fetch_blocks_by_range(block_number..block_number, json_rpc_named_arguments) do + {:ok, %Blocks{blocks_params: [%{timestamp: timestamp}]}} -> + day = DateTime.to_date(timestamp) + Map.put(map, "#{block_number}", day) + + _ -> + %{} + end + end) + end + + defp balances_daily_params(params_list, json_rpc_named_arguments) do + block_timestamp_map = block_timestamp_map(params_list, json_rpc_named_arguments) + + params_list + |> Enum.map(fn balance_param -> + if Map.has_key?(block_timestamp_map, "#{balance_param.block_number}") do + day = Map.get(block_timestamp_map, "#{balance_param.block_number}") + + incoming_balance_daily_param = %{ + address_hash: balance_param.address_hash, + day: day, + value: balance_param.value + } + + incoming_balance_daily_param + else + nil + end + end) + end end From 4212a56cb35b5bd362c9614241a62160ba1bf57a Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Tue, 19 Apr 2022 12:19:43 +0300 Subject: [PATCH 055/128] Remove duplicate of balances_params_to_address_params function --- CHANGELOG.md | 1 + apps/indexer/lib/indexer/fetcher/contract_code.ex | 13 ++----------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1a4ec85b516..47e5dd340ed2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ - [#5239](https://github.com/blockscout/blockscout/pull/5239) - Add accounting for block rewards in `getblockreward` api method ### Chore +- [#5480](https://github.com/blockscout/blockscout/pull/5480) - Remove duplicate of balances_params_to_address_params function - [#5473](https://github.com/blockscout/blockscout/pull/5473) - Refactor daily coin balances fetcher - [#5458](https://github.com/blockscout/blockscout/pull/5458) - Decrease min safe polling period for realtime fetcher - [#5456](https://github.com/blockscout/blockscout/pull/5456) - Ignore arbitrary block details fields for custom Ethereum clients diff --git a/apps/indexer/lib/indexer/fetcher/contract_code.ex b/apps/indexer/lib/indexer/fetcher/contract_code.ex index cd9a5baa0885..8f1247410761 100644 --- a/apps/indexer/lib/indexer/fetcher/contract_code.ex +++ b/apps/indexer/lib/indexer/fetcher/contract_code.ex @@ -14,6 +14,7 @@ defmodule Indexer.Fetcher.ContractCode do alias Explorer.Chain.{Block, Hash} alias Explorer.Chain.Cache.Accounts alias Indexer.{BufferedTask, Tracer} + alias Indexer.Fetcher.CoinBalance, as: CoinBalanceFetcher alias Indexer.Transform.Addresses @behaviour BufferedTask @@ -119,7 +120,7 @@ defmodule Indexer.Fetcher.ContractCode do |> EthereumJSONRPC.fetch_balances(json_rpc_named_arguments) |> case do {:ok, fetched_balances} -> - balance_addresses_params = balances_params_to_address_params(fetched_balances.params_list) + balance_addresses_params = CoinBalanceFetcher.balances_params_to_address_params(fetched_balances.params_list) merged_addresses_params = Addresses.merge_addresses(addresses_params ++ balance_addresses_params) @@ -154,16 +155,6 @@ defmodule Indexer.Fetcher.ContractCode do end end - def balances_params_to_address_params(balances_params) do - balances_params - |> Enum.group_by(fn %{address_hash: address_hash} -> address_hash end) - |> Map.values() - |> Stream.map(&Enum.max_by(&1, fn %{block_number: block_number} -> block_number end)) - |> Enum.map(fn %{address_hash: address_hash, block_number: block_number, value: value} -> - %{hash: address_hash, fetched_coin_balance_block_number: block_number, fetched_coin_balance: value} - end) - end - defp coin_balances_request_params(entries) do Enum.map(entries, fn {block_number, created_contract_address_hash_bytes, _transaction_hash_bytes} -> {:ok, created_contract_address_hash} = Hash.Address.cast(created_contract_address_hash_bytes) From 3e482a9d0d5df72d0d1d338d569ac5ffe5834398 Mon Sep 17 00:00:00 2001 From: nikitosing Date: Fri, 22 Apr 2022 10:32:00 +0300 Subject: [PATCH 056/128] Split long contract output to multiple lines --- CHANGELOG.md | 1 + .../templates/smart_contract/_functions.html.eex | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47e5dd340ed2..becfafe6c61c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - [#5268](https://github.com/blockscout/blockscout/pull/5268) - Contract names display improvement ### Fixes +- [#5488](https://github.com/blockscout/blockscout/pull/5488) - Split long contract output to multiple lines - [#5455](https://github.com/blockscout/blockscout/pull/5455) - Fix unverified_smart_contract function: add md5 of bytecode to the changeset - [#5454](https://github.com/blockscout/blockscout/pull/5454) - Docker: Fix the qemu-x86_64 signal 11 error on Apple Silicon - [#5443](https://github.com/blockscout/blockscout/pull/5443) - Geth: display tx revert reason diff --git a/apps/block_scout_web/lib/block_scout_web/templates/smart_contract/_functions.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/smart_contract/_functions.html.eex index 191c9836e0be..baf0c0ebc0a8 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/smart_contract/_functions.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/smart_contract/_functions.html.eex @@ -148,7 +148,7 @@
<% else %> -
"><%= raw(values_with_type(output["value"], output["type"], [output["name"]], 0, output["components"])) %>
+
"><%= raw(values_with_type(output["value"], output["type"], [output["name"]], 0, output["components"])) %>
<% end %> <% end %> <% end %> From 98722a92528618de82dde9d401d6177fb84693ad Mon Sep 17 00:00:00 2001 From: nikitosing Date: Sat, 12 Mar 2022 20:16:04 +0300 Subject: [PATCH 057/128] Add name for the proxy implementation on address page --- .../controllers/smart_contract_controller.ex | 6 ++++-- .../templates/address/overview.html.eex | 4 ++-- apps/explorer/lib/explorer/chain.ex | 12 ++++++------ apps/explorer/lib/explorer/etherscan/contracts.ex | 5 ++++- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/smart_contract_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/smart_contract_controller.ex index 621dd661cdf5..c90d43143636 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/smart_contract_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/smart_contract_controller.ex @@ -18,8 +18,10 @@ defmodule BlockScoutWeb.SmartContractController do {:ok, address} <- Chain.find_contract_address(address_hash, address_options, true) do implementation_address_hash_string = if contract_type == "proxy" do - Chain.get_implementation_address_hash(address.hash, address.smart_contract.abi) || - @burn_address + (address.hash + |> Chain.get_implementation_address_hash(address.smart_contract.abi) + |> Tuple.to_list() + |> List.first()) || @burn_address else @burn_address end diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address/overview.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address/overview.html.eex index 1b323535751c..d0a8b3a751a0 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address/overview.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address/overview.html.eex @@ -141,7 +141,7 @@ <% end %> <%= if @is_proxy do %> - <% implementation_address = Chain.get_implementation_address_hash(@address.hash, @address.smart_contract.abi) || "0x0000000000000000000000000000000000000000" %> + <% {implementation_address, name} = Chain.get_implementation_address_hash(@address.hash, @address.smart_contract.abi) || "0x0000000000000000000000000000000000000000" %>
<%= render BlockScoutWeb.CommonComponentsView, "_i_tooltip_2.html", @@ -150,7 +150,7 @@
<%= link( - implementation_address, + (if name, do: name <> " | " <> implementation_address, else: implementation_address), to: address_path(@conn, :show, implementation_address), class: "contract-address" ) diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index 3f25f63e99ae..4d33844f9f01 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -6667,7 +6667,7 @@ defmodule Explorer.Chain do def gnosis_safe_contract?(abi) when is_nil(abi), do: false - @spec get_implementation_address_hash(Hash.Address.t(), list()) :: String.t() | nil + @spec get_implementation_address_hash(Hash.Address.t(), list()) :: {String.t() | nil, String.t() | nil} def get_implementation_address_hash(proxy_address_hash, abi) when not is_nil(proxy_address_hash) and not is_nil(abi) do implementation_method_abi = @@ -6698,7 +6698,7 @@ defmodule Explorer.Chain do end def get_implementation_address_hash(proxy_address_hash, abi) when is_nil(proxy_address_hash) or is_nil(abi) do - nil + {nil, nil} end defp get_implementation_address_hash_eip_1967(proxy_address_hash) do @@ -6855,7 +6855,7 @@ defmodule Explorer.Chain do "0x0000000000000000000000000000000000000000000000000000000000000000", @burn_address_hash_str ], - do: empty_address_hash_string + do: {empty_address_hash_string, nil} defp save_implementation_name(implementation_address_hash_string, proxy_address_hash) when is_binary(implementation_address_hash_string) do @@ -6866,10 +6866,10 @@ defmodule Explorer.Chain do |> update(set: [implementation_name: ^name]) |> Repo.update_all([]) - implementation_address_hash_string + {implementation_address_hash_string, name} else _ -> - implementation_address_hash_string + {implementation_address_hash_string, nil} end end @@ -6924,7 +6924,7 @@ defmodule Explorer.Chain do def get_implementation_abi_from_proxy(proxy_address_hash, abi) when not is_nil(proxy_address_hash) and not is_nil(abi) do - implementation_address_hash_string = get_implementation_address_hash(proxy_address_hash, abi) + {implementation_address_hash_string, _name} = get_implementation_address_hash(proxy_address_hash, abi) get_implementation_abi(implementation_address_hash_string) end diff --git a/apps/explorer/lib/explorer/etherscan/contracts.ex b/apps/explorer/lib/explorer/etherscan/contracts.ex index d224294e0376..37e8ef7a34a9 100644 --- a/apps/explorer/lib/explorer/etherscan/contracts.ex +++ b/apps/explorer/lib/explorer/etherscan/contracts.ex @@ -64,7 +64,10 @@ defmodule Explorer.Etherscan.Contracts do |> Map.put(:is_proxy, true) |> Map.put( :implementation_address_hash_string, - Chain.get_implementation_address_hash(address.hash, smart_contract.abi) + address.hash + |> Chain.get_implementation_address_hash(smart_contract.abi) + |> Tuple.to_list() + |> List.first() ) else smart_contract From 16788aad5326c74039b298ec4c8c55a3e4db744f Mon Sep 17 00:00:00 2001 From: nikitosing Date: Sat, 12 Mar 2022 21:15:50 +0300 Subject: [PATCH 058/128] Add contract's name to logs (transaction page) --- CHANGELOG.md | 2 +- .../controllers/smart_contract_controller.ex | 4 ++-- .../controllers/transaction_log_controller.ex | 2 ++ .../templates/transaction_log/_logs.html.eex | 3 ++- .../block_scout_web/views/transaction_log_view.ex | 1 + apps/block_scout_web/priv/gettext/default.pot | 12 ++++++------ .../priv/gettext/en/LC_MESSAGES/default.po | 12 ++++++------ apps/explorer/lib/explorer/chain.ex | 2 +- 8 files changed, 21 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47e5dd340ed2..0b336fd4495c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ### Features - [#5312](https://github.com/blockscout/blockscout/pull/5312) - Add OpenZeppelin proxy storage slot - [#5302](https://github.com/blockscout/blockscout/pull/5302) - Add specific tx receipt fields for the GoQuorum client -- [#5268](https://github.com/blockscout/blockscout/pull/5268) - Contract names display improvement +- [#5268](https://github.com/blockscout/blockscout/pull/5268), [#5313](https://github.com/blockscout/blockscout/pull/5313) - Contract names display improvement ### Fixes - [#5455](https://github.com/blockscout/blockscout/pull/5455) - Fix unverified_smart_contract function: add md5 of bytecode to the changeset diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/smart_contract_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/smart_contract_controller.ex index c90d43143636..59121293f144 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/smart_contract_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/smart_contract_controller.ex @@ -18,10 +18,10 @@ defmodule BlockScoutWeb.SmartContractController do {:ok, address} <- Chain.find_contract_address(address_hash, address_options, true) do implementation_address_hash_string = if contract_type == "proxy" do - (address.hash + address.hash |> Chain.get_implementation_address_hash(address.smart_contract.abi) |> Tuple.to_list() - |> List.first()) || @burn_address + |> List.first() || @burn_address else @burn_address end diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_log_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_log_controller.ex index a5ba2959d179..f9abbf207b78 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_log_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_log_controller.ex @@ -20,6 +20,8 @@ defmodule BlockScoutWeb.TransactionLogController do Keyword.merge( [ necessity_by_association: %{ + [address: :names] => :optional, + [address: :smart_contract] => :optional, address: :optional } ], diff --git a/apps/block_scout_web/lib/block_scout_web/templates/transaction_log/_logs.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/transaction_log/_logs.html.eex index 1813358d3481..2b1b4e0d35a0 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/transaction_log/_logs.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/transaction_log/_logs.html.eex @@ -20,8 +20,9 @@
<%= gettext "Address" %>

+ <% name = implementation_name(@log.address) || primary_name(@log.address)%> <%= link( - @log.address, + (if name, do: name <> " | "<> to_string(@log.address), else: @log.address), to: address_path(@conn, :show, @log.address), "data-test": "log_address_link", "data-address-hash": @log.address diff --git a/apps/block_scout_web/lib/block_scout_web/views/transaction_log_view.ex b/apps/block_scout_web/lib/block_scout_web/views/transaction_log_view.ex index 50d406433ce1..e494bbd88934 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/transaction_log_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/transaction_log_view.ex @@ -3,6 +3,7 @@ defmodule BlockScoutWeb.TransactionLogView do @dialyzer :no_match alias Explorer.Chain.Log + import BlockScoutWeb.AddressView, only: [implementation_name: 1, primary_name: 1] def decode(log, transaction) do Log.decode(log, transaction) diff --git a/apps/block_scout_web/priv/gettext/default.pot b/apps/block_scout_web/priv/gettext/default.pot index 900b502a09e8..321a607d8527 100644 --- a/apps/block_scout_web/priv/gettext/default.pot +++ b/apps/block_scout_web/priv/gettext/default.pot @@ -881,7 +881,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/address_logs/_logs.html.eex:101 #: lib/block_scout_web/templates/log/_data_decoded_view.html.eex:7 lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:23 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:120 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:121 msgid "Data" msgstr "" @@ -904,8 +904,8 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/address_logs/_logs.html.eex:32 #: lib/block_scout_web/templates/address_logs/_logs.html.eex:38 lib/block_scout_web/templates/address_logs/_logs.html.eex:53 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:33 lib/block_scout_web/templates/transaction_log/_logs.html.eex:41 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:56 lib/block_scout_web/templates/transaction_log/_logs.html.eex:72 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:34 lib/block_scout_web/templates/transaction_log/_logs.html.eex:42 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:57 lib/block_scout_web/templates/transaction_log/_logs.html.eex:73 msgid "Decoded" msgstr "" @@ -1154,7 +1154,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/address_logs/_logs.html.eex:35 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:36 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:37 msgid "Failed to decode log data." msgstr "" @@ -1485,7 +1485,7 @@ msgid "Log Data" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:130 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:131 msgid "Log Index" msgstr "" @@ -2685,7 +2685,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/address_logs/_logs.html.eex:71 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:90 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:91 msgid "Topics" msgstr "" diff --git a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po index 900b502a09e8..321a607d8527 100644 --- a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po +++ b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po @@ -881,7 +881,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/address_logs/_logs.html.eex:101 #: lib/block_scout_web/templates/log/_data_decoded_view.html.eex:7 lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:23 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:120 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:121 msgid "Data" msgstr "" @@ -904,8 +904,8 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/address_logs/_logs.html.eex:32 #: lib/block_scout_web/templates/address_logs/_logs.html.eex:38 lib/block_scout_web/templates/address_logs/_logs.html.eex:53 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:33 lib/block_scout_web/templates/transaction_log/_logs.html.eex:41 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:56 lib/block_scout_web/templates/transaction_log/_logs.html.eex:72 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:34 lib/block_scout_web/templates/transaction_log/_logs.html.eex:42 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:57 lib/block_scout_web/templates/transaction_log/_logs.html.eex:73 msgid "Decoded" msgstr "" @@ -1154,7 +1154,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/address_logs/_logs.html.eex:35 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:36 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:37 msgid "Failed to decode log data." msgstr "" @@ -1485,7 +1485,7 @@ msgid "Log Data" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:130 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:131 msgid "Log Index" msgstr "" @@ -2685,7 +2685,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/address_logs/_logs.html.eex:71 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:90 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:91 msgid "Topics" msgstr "" diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index 4d33844f9f01..559ae110995d 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -6873,7 +6873,7 @@ defmodule Explorer.Chain do end end - defp save_implementation_name(other, _), do: other + defp save_implementation_name(other, _), do: {other, nil} defp abi_decode_address_output(nil), do: nil From a3fce6766532c2ef2d361f847bb160bc856ceed2 Mon Sep 17 00:00:00 2001 From: nikitosing Date: Thu, 17 Mar 2022 21:23:08 +0300 Subject: [PATCH 059/128] Ignore implementation name on an internal transaction tile --- .../lib/block_scout_web/templates/address/_link.html.eex | 2 +- .../templates/address/_responsive_hash.html.eex | 2 +- .../templates/internal_transaction/_tile.html.eex | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address/_link.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address/_link.html.eex index 8a7c4123653e..e1272aee7699 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address/_link.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address/_link.html.eex @@ -1,6 +1,6 @@ <%= if @address do %> <%= if assigns[:show_full_hash] do %> - <%= if name = implementation_name(@address) || primary_name(@address) do %> + <%= if name = if assigns[:ignore_implementation_name], do: implementation_name(@address) || primary_name(@address), else: primary_name(@address) do %> <%= name %> | <% end %> <%= link to: address_path(BlockScoutWeb.Endpoint, :show, @address), "data-test": "address_hash_link", class: assigns[:class] do %> diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address/_responsive_hash.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address/_responsive_hash.html.eex index 85aa6dfc85ad..168e68da36a6 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address/_responsive_hash.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address/_responsive_hash.html.eex @@ -1,5 +1,5 @@ - <%= if name = implementation_name(@address) || primary_name(@address) do %> + <%= if name = if assigns[:ignore_implementation_name], do: implementation_name(@address) || primary_name(@address), else: primary_name(@address) do %> <%= if assigns[:no_tooltip] do %> <%= if @use_custom_tooltip == true do %> <%= name %> (<%= short_hash(@address) %>...) diff --git a/apps/block_scout_web/lib/block_scout_web/templates/internal_transaction/_tile.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/internal_transaction/_tile.html.eex index 63fbe96bcb0c..73b08b37a33f 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/internal_transaction/_tile.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/internal_transaction/_tile.html.eex @@ -15,9 +15,9 @@
<%= render BlockScoutWeb.TransactionView, "_link.html", transaction_hash: @internal_transaction.transaction_hash %> - <%= @internal_transaction |> BlockScoutWeb.AddressView.address_partial_selector(:from, assigns[:current_address]) |> BlockScoutWeb.RenderHelpers.render_partial() %> + <%= @internal_transaction |> BlockScoutWeb.AddressView.address_partial_selector(:from, assigns[:current_address]) |> Keyword.put(:ignore_implementation_name, true) |> BlockScoutWeb.RenderHelpers.render_partial() %> → - <%= @internal_transaction |> BlockScoutWeb.AddressView.address_partial_selector(:to, assigns[:current_address]) |> BlockScoutWeb.RenderHelpers.render_partial() %> + <%= @internal_transaction |> BlockScoutWeb.AddressView.address_partial_selector(:to, assigns[:current_address]) |> Keyword.put(:ignore_implementation_name, true) |> BlockScoutWeb.RenderHelpers.render_partial() %> From 284e064fedae25670ee172e0ed0cb544be460d20 Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Fri, 22 Apr 2022 19:45:18 +0300 Subject: [PATCH 060/128] Fix array displaying in decoded constructor args --- CHANGELOG.md | 1 + .../views/address_contract_view.ex | 41 ++++++++++++------- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index becfafe6c61c..468e88369631 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ ### Fixes - [#5488](https://github.com/blockscout/blockscout/pull/5488) - Split long contract output to multiple lines +- [#5487](https://github.com/blockscout/blockscout/pull/5487) - Fix array displaying in decoded constructor args - [#5455](https://github.com/blockscout/blockscout/pull/5455) - Fix unverified_smart_contract function: add md5 of bytecode to the changeset - [#5454](https://github.com/blockscout/blockscout/pull/5454) - Docker: Fix the qemu-x86_64 signal 11 error on Apple Silicon - [#5443](https://github.com/blockscout/blockscout/pull/5443) - Geth: display tx revert reason diff --git a/apps/block_scout_web/lib/block_scout_web/views/address_contract_view.ex b/apps/block_scout_web/lib/block_scout_web/views/address_contract_view.ex index f26debafc200..7c7162719597 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/address_contract_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/address_contract_view.ex @@ -33,21 +33,7 @@ defmodule BlockScoutWeb.AddressContractView do |> decode_data(input_types) |> Enum.zip(constructor_abi["inputs"]) |> Enum.reduce({0, "#{contract.constructor_arguments}\n\n"}, fn {val, %{"type" => type}}, {count, acc} -> - formatted_val = - cond do - type =~ "address" -> - address_hash = "0x" <> Base.encode16(val, case: :lower) - - address = get_address(address_hash) - - get_formatted_address_data(address, address_hash, conn) - - type =~ "bytes" -> - Base.encode16(val, case: :lower) - - true -> - val - end + formatted_val = val_to_string(val, type, conn) {count + 1, "#{acc}Arg [#{count}] (#{type}) : #{formatted_val}\n"} end) @@ -57,6 +43,31 @@ defmodule BlockScoutWeb.AddressContractView do _ -> contract.constructor_arguments end + defp val_to_string(val, type, conn) do + cond do + type =~ "[]" -> + if is_list(val) or is_tuple(val) do + "[" <> + Enum.map_join(val, ", ", fn el -> val_to_string(el, String.replace_suffix(type, "[]", ""), conn) end) <> "]" + else + to_string(val) + end + + type =~ "address" -> + address_hash = "0x" <> Base.encode16(val, case: :lower) + + address = get_address(address_hash) + + get_formatted_address_data(address, address_hash, conn) + + type =~ "bytes" -> + Base.encode16(val, case: :lower) + + true -> + to_string(val) + end + end + defp get_address(address_hash) do case Chain.string_to_address_hash(address_hash) do {:ok, address} -> address From 5fb32290cd6b0e06db6f3ddee943f3d1a6b94906 Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Fri, 22 Apr 2022 17:54:17 +0300 Subject: [PATCH 061/128] Sequential blocks broadcast --- CHANGELOG.md | 1 + .../lib/block_scout_web/notifier.ex | 41 ++++++++++++++++++- .../block_scout_web/realtime_event_handler.ex | 2 + 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 468e88369631..1525f6a3c1a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## Current ### Features +- [#5491](https://github.com/blockscout/blockscout/pull/5491) - Sequential blocks broadcast on the main page - [#5312](https://github.com/blockscout/blockscout/pull/5312) - Add OpenZeppelin proxy storage slot - [#5302](https://github.com/blockscout/blockscout/pull/5302) - Add specific tx receipt fields for the GoQuorum client - [#5268](https://github.com/blockscout/blockscout/pull/5268) - Contract names display improvement diff --git a/apps/block_scout_web/lib/block_scout_web/notifier.ex b/apps/block_scout_web/lib/block_scout_web/notifier.ex index b22d34cd29a5..3c732093fade 100644 --- a/apps/block_scout_web/lib/block_scout_web/notifier.ex +++ b/apps/block_scout_web/lib/block_scout_web/notifier.ex @@ -17,11 +17,13 @@ defmodule BlockScoutWeb.Notifier do alias Explorer.Chain.{Address, InternalTransaction, TokenTransfer, Transaction} alias Explorer.Chain.Supply.RSK alias Explorer.Chain.Transaction.History.TransactionStats - alias Explorer.Counters.AverageBlockTime + alias Explorer.Counters.{AverageBlockTime, Helper} alias Explorer.ExchangeRates.Token alias Explorer.SmartContract.{CompilerVersion, Solidity.CodeCompiler} alias Phoenix.View + @check_broadcast_sequence_period 500 + def handle_event({:chain_event, :addresses, type, addresses}) when type in [:realtime, :on_demand] do Endpoint.broadcast("addresses:new_address", "count", %{count: Chain.address_estimated_count()}) @@ -87,7 +89,13 @@ defmodule BlockScoutWeb.Notifier do end def handle_event({:chain_event, :blocks, :realtime, blocks}) do - Enum.each(blocks, &broadcast_block/1) + last_broadcasted_block_number = Helper.fetch_from_cache(:number, :last_broadcasted_block) + + blocks + |> Enum.sort_by(& &1.number, :asc) + |> Enum.each(fn block -> + broadcast_latest_block?(block, last_broadcasted_block_number) + end) end def handle_event({:chain_event, :exchange_rate}) do @@ -229,6 +237,35 @@ defmodule BlockScoutWeb.Notifier do }) end + defp broadcast_latest_block?(block, last_broadcasted_block_number) do + cond do + last_broadcasted_block_number == 0 || last_broadcasted_block_number == block.number - 1 || + last_broadcasted_block_number < block.number - 4 -> + broadcast_block(block) + :ets.insert(:last_broadcasted_block, {:number, block.number}) + + last_broadcasted_block_number > block.number - 1 -> + broadcast_block(block) + + true -> + Task.start_link(fn -> + schedule_broadcasting(block) + end) + end + end + + defp schedule_broadcasting(block) do + :timer.sleep(@check_broadcast_sequence_period) + last_broadcasted_block_number = Helper.fetch_from_cache(:number, :last_broadcasted_block) + + if last_broadcasted_block_number == block.number - 1 do + broadcast_block(block) + :ets.insert(:last_broadcasted_block, {:number, block.number}) + else + schedule_broadcasting(block) + end + end + defp broadcast_address_coin_balance(%{address_hash: address_hash, block_number: block_number}) do Endpoint.broadcast("addresses:#{address_hash}", "coin_balance", %{ block_number: block_number diff --git a/apps/block_scout_web/lib/block_scout_web/realtime_event_handler.ex b/apps/block_scout_web/lib/block_scout_web/realtime_event_handler.ex index 45126bace107..148bbbc4697d 100644 --- a/apps/block_scout_web/lib/block_scout_web/realtime_event_handler.ex +++ b/apps/block_scout_web/lib/block_scout_web/realtime_event_handler.ex @@ -7,6 +7,7 @@ defmodule BlockScoutWeb.RealtimeEventHandler do alias BlockScoutWeb.Notifier alias Explorer.Chain.Events.Subscriber + alias Explorer.Counters.Helper def start_link(_) do GenServer.start_link(__MODULE__, [], name: __MODULE__) @@ -14,6 +15,7 @@ defmodule BlockScoutWeb.RealtimeEventHandler do @impl true def init([]) do + Helper.create_cache_table(:last_broadcasted_block) Subscriber.to(:address_coin_balances, :realtime) Subscriber.to(:addresses, :realtime) Subscriber.to(:block_rewards, :realtime) From 7b0cd50e04847c4dad6263efa0640be442cbd39f Mon Sep 17 00:00:00 2001 From: nikitosing Date: Fri, 22 Apr 2022 21:22:17 +0300 Subject: [PATCH 062/128] Fix displaying own names on internal tx tiles --- .../templates/address/_link.html.eex | 4 +-- .../address/_responsive_hash.html.eex | 2 +- .../lib/block_scout_web/views/address_view.ex | 14 +++++++--- apps/block_scout_web/priv/gettext/default.pot | 26 +++++++++---------- .../priv/gettext/en/LC_MESSAGES/default.po | 26 +++++++++---------- 5 files changed, 39 insertions(+), 33 deletions(-) diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address/_link.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address/_link.html.eex index e1272aee7699..275a8f058dc1 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address/_link.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address/_link.html.eex @@ -1,6 +1,6 @@ <%= if @address do %> <%= if assigns[:show_full_hash] do %> - <%= if name = if assigns[:ignore_implementation_name], do: implementation_name(@address) || primary_name(@address), else: primary_name(@address) do %> + <%= if name = if assigns[:ignore_implementation_name], do: primary_name(@address), else: implementation_name(@address) || primary_name(@address) do %> <%= name %> | <% end %> <%= link to: address_path(BlockScoutWeb.Endpoint, :show, @address), "data-test": "address_hash_link", class: assigns[:class] do %> @@ -9,7 +9,7 @@ <% else %> <%= link to: address_path(BlockScoutWeb.Endpoint, :show, @address), "data-test": "address_hash_link", class: assigns[:class] do %> - <%= render BlockScoutWeb.AddressView, "_responsive_hash.html", address: @address, contract: @contract, truncate: assigns[:truncate], use_custom_tooltip: @use_custom_tooltip, no_tooltip: assigns[:no_tooltip], custom_classes_tooltip: assigns[:custom_classes_tooltip] %> + <%= render BlockScoutWeb.AddressView, "_responsive_hash.html", address: @address, contract: @contract, truncate: assigns[:truncate], use_custom_tooltip: @use_custom_tooltip, no_tooltip: assigns[:no_tooltip], custom_classes_tooltip: assigns[:custom_classes_tooltip], ignore_implementation_name: assigns[:ignore_implementation_name] %> <% end %> <% end %> <% end %> diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address/_responsive_hash.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address/_responsive_hash.html.eex index 168e68da36a6..06b0954cb05e 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address/_responsive_hash.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address/_responsive_hash.html.eex @@ -1,5 +1,5 @@ - <%= if name = if assigns[:ignore_implementation_name], do: implementation_name(@address) || primary_name(@address), else: primary_name(@address) do %> + <%= if name = if assigns[:ignore_implementation_name], do: primary_name(@address), else: implementation_name(@address) || primary_name(@address) do %> <%= if assigns[:no_tooltip] do %> <%= if @use_custom_tooltip == true do %> <%= name %> (<%= short_hash(@address) %>...) diff --git a/apps/block_scout_web/lib/block_scout_web/views/address_view.ex b/apps/block_scout_web/lib/block_scout_web/views/address_view.ex index d915238c4842..6c49191daefd 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/address_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/address_view.ex @@ -4,7 +4,7 @@ defmodule BlockScoutWeb.AddressView do require Logger alias BlockScoutWeb.{AccessHelpers, LayoutView} - alias Explorer.{Chain, CustomContractsHelpers} + alias Explorer.{Chain, CustomContractsHelpers, Repo} alias Explorer.Chain.{Address, Hash, InternalTransaction, SmartContract, Token, TokenTransfer, Transaction, Wei} alias Explorer.Chain.Block.Reward alias Explorer.ExchangeRates.Token, as: TokenExchangeRate @@ -176,9 +176,11 @@ defmodule BlockScoutWeb.AddressView do end @doc """ - Returns the primary name of an address if available. + Returns the primary name of an address if available. If there is no names on address function performs preload of names association. """ - def primary_name(%Address{names: [_ | _] = address_names}) do + def primary_name(_, second_time? \\ false) + + def primary_name(%Address{names: [_ | _] = address_names}, _second_time?) do case Enum.find(address_names, &(&1.primary == true)) do nil -> %Address.Name{name: name} = Enum.at(address_names, 0) @@ -189,7 +191,11 @@ defmodule BlockScoutWeb.AddressView do end end - def primary_name(%Address{names: _}), do: nil + def primary_name(%Address{names: _} = address, false) do + primary_name(Repo.preload(address, [:names]), true) + end + + def primary_name(%Address{names: _}, true), do: nil def implementation_name(%Address{smart_contract: %{implementation_name: implementation_name}}), do: implementation_name diff --git a/apps/block_scout_web/priv/gettext/default.pot b/apps/block_scout_web/priv/gettext/default.pot index 321a607d8527..fe7b187da31f 100644 --- a/apps/block_scout_web/priv/gettext/default.pot +++ b/apps/block_scout_web/priv/gettext/default.pot @@ -430,7 +430,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/address/_tabs.html.eex:48 #: lib/block_scout_web/templates/address/overview.html.eex:290 lib/block_scout_web/templates/address_validation/index.html.eex:11 -#: lib/block_scout_web/views/address_view.ex:365 +#: lib/block_scout_web/views/address_view.ex:371 msgid "Blocks Validated" msgstr "" @@ -569,13 +569,13 @@ msgstr "" #: lib/block_scout_web/templates/address/_tabs.html.eex:58 #: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:165 lib/block_scout_web/templates/api_docs/_action_tile.html.eex:187 #: lib/block_scout_web/templates/api_docs/_eth_rpc_item.html.eex:126 lib/block_scout_web/templates/api_docs/_eth_rpc_item.html.eex:149 -#: lib/block_scout_web/views/address_view.ex:358 +#: lib/block_scout_web/views/address_view.ex:364 msgid "Code" msgstr "" #, elixir-format #: lib/block_scout_web/templates/address/_tabs.html.eex:34 -#: lib/block_scout_web/views/address_view.ex:364 +#: lib/block_scout_web/views/address_view.ex:370 msgid "Coin Balance History" msgstr "" @@ -910,7 +910,7 @@ msgid "Decoded" msgstr "" #, elixir-format -#: lib/block_scout_web/views/address_view.ex:359 +#: lib/block_scout_web/views/address_view.ex:365 msgid "Decompiled Code" msgstr "" @@ -1377,7 +1377,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/address/_tabs.html.eex:28 #: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:17 lib/block_scout_web/templates/transaction/_tabs.html.eex:11 -#: lib/block_scout_web/templates/transaction_internal_transaction/index.html.eex:6 lib/block_scout_web/views/address_view.ex:355 +#: lib/block_scout_web/templates/transaction_internal_transaction/index.html.eex:6 lib/block_scout_web/views/address_view.ex:361 #: lib/block_scout_web/views/transaction_view.ex:512 msgid "Internal Transactions" msgstr "" @@ -1492,7 +1492,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/address/_tabs.html.eex:41 #: lib/block_scout_web/templates/address_logs/index.html.eex:10 lib/block_scout_web/templates/transaction/_tabs.html.eex:17 -#: lib/block_scout_web/templates/transaction_log/index.html.eex:8 lib/block_scout_web/views/address_view.ex:366 +#: lib/block_scout_web/templates/transaction_log/index.html.eex:8 lib/block_scout_web/views/address_view.ex:372 #: lib/block_scout_web/views/transaction_view.ex:513 msgid "Logs" msgstr "" @@ -1933,14 +1933,14 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/address/_tabs.html.eex:81 -#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:27 lib/block_scout_web/views/address_view.ex:360 +#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:27 lib/block_scout_web/views/address_view.ex:366 #: lib/block_scout_web/views/tokens/overview_view.ex:43 msgid "Read Contract" msgstr "" #, elixir-format #: lib/block_scout_web/templates/address/_tabs.html.eex:88 -#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:41 lib/block_scout_web/views/address_view.ex:361 +#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:41 lib/block_scout_web/views/address_view.ex:367 msgid "Read Proxy" msgstr "" @@ -2628,7 +2628,7 @@ msgstr "" #: lib/block_scout_web/templates/address_token_transfer/index.html.eex:19 lib/block_scout_web/templates/tokens/instance/overview/_tabs.html.eex:3 #: lib/block_scout_web/templates/tokens/instance/transfer/index.html.eex:16 lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:5 #: lib/block_scout_web/templates/tokens/transfer/index.html.eex:14 lib/block_scout_web/templates/transaction/_tabs.html.eex:4 -#: lib/block_scout_web/templates/transaction_token_transfer/index.html.eex:7 lib/block_scout_web/views/address_view.ex:357 +#: lib/block_scout_web/templates/transaction_token_transfer/index.html.eex:7 lib/block_scout_web/views/address_view.ex:363 #: lib/block_scout_web/views/tokens/instance/overview_view.ex:195 lib/block_scout_web/views/tokens/overview_view.ex:41 #: lib/block_scout_web/views/transaction_view.ex:511 msgid "Token Transfers" @@ -2649,7 +2649,7 @@ msgstr "" #: lib/block_scout_web/templates/address/overview.html.eex:191 lib/block_scout_web/templates/address_token/overview.html.eex:58 #: lib/block_scout_web/templates/address_token_transfer/index.html.eex:13 lib/block_scout_web/templates/layout/_topnav.html.eex:69 #: lib/block_scout_web/templates/layout/_topnav.html.eex:101 lib/block_scout_web/templates/tokens/index.html.eex:10 -#: lib/block_scout_web/views/address_view.ex:354 +#: lib/block_scout_web/views/address_view.ex:360 msgid "Tokens" msgstr "" @@ -2797,7 +2797,7 @@ msgstr "" #: lib/block_scout_web/templates/address/overview.html.eex:216 lib/block_scout_web/templates/address_transaction/index.html.eex:13 #: lib/block_scout_web/templates/block/overview.html.eex:80 lib/block_scout_web/templates/block_transaction/index.html.eex:10 #: lib/block_scout_web/templates/chain/show.html.eex:236 lib/block_scout_web/templates/layout/_topnav.html.eex:43 -#: lib/block_scout_web/views/address_view.ex:356 +#: lib/block_scout_web/views/address_view.ex:362 msgid "Transactions" msgstr "" @@ -3139,13 +3139,13 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/address/_tabs.html.eex:95 -#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:34 lib/block_scout_web/views/address_view.ex:362 +#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:34 lib/block_scout_web/views/address_view.ex:368 msgid "Write Contract" msgstr "" #, elixir-format #: lib/block_scout_web/templates/address/_tabs.html.eex:102 -#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:48 lib/block_scout_web/views/address_view.ex:363 +#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:48 lib/block_scout_web/views/address_view.ex:369 msgid "Write Proxy" msgstr "" diff --git a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po index 321a607d8527..fe7b187da31f 100644 --- a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po +++ b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po @@ -430,7 +430,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/address/_tabs.html.eex:48 #: lib/block_scout_web/templates/address/overview.html.eex:290 lib/block_scout_web/templates/address_validation/index.html.eex:11 -#: lib/block_scout_web/views/address_view.ex:365 +#: lib/block_scout_web/views/address_view.ex:371 msgid "Blocks Validated" msgstr "" @@ -569,13 +569,13 @@ msgstr "" #: lib/block_scout_web/templates/address/_tabs.html.eex:58 #: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:165 lib/block_scout_web/templates/api_docs/_action_tile.html.eex:187 #: lib/block_scout_web/templates/api_docs/_eth_rpc_item.html.eex:126 lib/block_scout_web/templates/api_docs/_eth_rpc_item.html.eex:149 -#: lib/block_scout_web/views/address_view.ex:358 +#: lib/block_scout_web/views/address_view.ex:364 msgid "Code" msgstr "" #, elixir-format #: lib/block_scout_web/templates/address/_tabs.html.eex:34 -#: lib/block_scout_web/views/address_view.ex:364 +#: lib/block_scout_web/views/address_view.ex:370 msgid "Coin Balance History" msgstr "" @@ -910,7 +910,7 @@ msgid "Decoded" msgstr "" #, elixir-format -#: lib/block_scout_web/views/address_view.ex:359 +#: lib/block_scout_web/views/address_view.ex:365 msgid "Decompiled Code" msgstr "" @@ -1377,7 +1377,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/address/_tabs.html.eex:28 #: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:17 lib/block_scout_web/templates/transaction/_tabs.html.eex:11 -#: lib/block_scout_web/templates/transaction_internal_transaction/index.html.eex:6 lib/block_scout_web/views/address_view.ex:355 +#: lib/block_scout_web/templates/transaction_internal_transaction/index.html.eex:6 lib/block_scout_web/views/address_view.ex:361 #: lib/block_scout_web/views/transaction_view.ex:512 msgid "Internal Transactions" msgstr "" @@ -1492,7 +1492,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/address/_tabs.html.eex:41 #: lib/block_scout_web/templates/address_logs/index.html.eex:10 lib/block_scout_web/templates/transaction/_tabs.html.eex:17 -#: lib/block_scout_web/templates/transaction_log/index.html.eex:8 lib/block_scout_web/views/address_view.ex:366 +#: lib/block_scout_web/templates/transaction_log/index.html.eex:8 lib/block_scout_web/views/address_view.ex:372 #: lib/block_scout_web/views/transaction_view.ex:513 msgid "Logs" msgstr "" @@ -1933,14 +1933,14 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/address/_tabs.html.eex:81 -#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:27 lib/block_scout_web/views/address_view.ex:360 +#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:27 lib/block_scout_web/views/address_view.ex:366 #: lib/block_scout_web/views/tokens/overview_view.ex:43 msgid "Read Contract" msgstr "" #, elixir-format #: lib/block_scout_web/templates/address/_tabs.html.eex:88 -#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:41 lib/block_scout_web/views/address_view.ex:361 +#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:41 lib/block_scout_web/views/address_view.ex:367 msgid "Read Proxy" msgstr "" @@ -2628,7 +2628,7 @@ msgstr "" #: lib/block_scout_web/templates/address_token_transfer/index.html.eex:19 lib/block_scout_web/templates/tokens/instance/overview/_tabs.html.eex:3 #: lib/block_scout_web/templates/tokens/instance/transfer/index.html.eex:16 lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:5 #: lib/block_scout_web/templates/tokens/transfer/index.html.eex:14 lib/block_scout_web/templates/transaction/_tabs.html.eex:4 -#: lib/block_scout_web/templates/transaction_token_transfer/index.html.eex:7 lib/block_scout_web/views/address_view.ex:357 +#: lib/block_scout_web/templates/transaction_token_transfer/index.html.eex:7 lib/block_scout_web/views/address_view.ex:363 #: lib/block_scout_web/views/tokens/instance/overview_view.ex:195 lib/block_scout_web/views/tokens/overview_view.ex:41 #: lib/block_scout_web/views/transaction_view.ex:511 msgid "Token Transfers" @@ -2649,7 +2649,7 @@ msgstr "" #: lib/block_scout_web/templates/address/overview.html.eex:191 lib/block_scout_web/templates/address_token/overview.html.eex:58 #: lib/block_scout_web/templates/address_token_transfer/index.html.eex:13 lib/block_scout_web/templates/layout/_topnav.html.eex:69 #: lib/block_scout_web/templates/layout/_topnav.html.eex:101 lib/block_scout_web/templates/tokens/index.html.eex:10 -#: lib/block_scout_web/views/address_view.ex:354 +#: lib/block_scout_web/views/address_view.ex:360 msgid "Tokens" msgstr "" @@ -2797,7 +2797,7 @@ msgstr "" #: lib/block_scout_web/templates/address/overview.html.eex:216 lib/block_scout_web/templates/address_transaction/index.html.eex:13 #: lib/block_scout_web/templates/block/overview.html.eex:80 lib/block_scout_web/templates/block_transaction/index.html.eex:10 #: lib/block_scout_web/templates/chain/show.html.eex:236 lib/block_scout_web/templates/layout/_topnav.html.eex:43 -#: lib/block_scout_web/views/address_view.ex:356 +#: lib/block_scout_web/views/address_view.ex:362 msgid "Transactions" msgstr "" @@ -3139,13 +3139,13 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/address/_tabs.html.eex:95 -#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:34 lib/block_scout_web/views/address_view.ex:362 +#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:34 lib/block_scout_web/views/address_view.ex:368 msgid "Write Contract" msgstr "" #, elixir-format #: lib/block_scout_web/templates/address/_tabs.html.eex:102 -#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:48 lib/block_scout_web/views/address_view.ex:363 +#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:48 lib/block_scout_web/views/address_view.ex:369 msgid "Write Proxy" msgstr "" From 2ef9e87ed84fc351090d495db7215f5054b9ecf9 Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Fri, 22 Apr 2022 21:50:37 +0300 Subject: [PATCH 063/128] Split multiple functions arguments to separate query args --- CHANGELOG.md | 1 + .../assets/js/lib/smart_contract/interact.js | 21 ++++++++++--------- .../controllers/smart_contract_controller.ex | 8 +++++-- .../smart_contract_controller_test.exs | 1 + 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 468e88369631..030d7ac25fd5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ ### Fixes - [#5488](https://github.com/blockscout/blockscout/pull/5488) - Split long contract output to multiple lines - [#5487](https://github.com/blockscout/blockscout/pull/5487) - Fix array displaying in decoded constructor args +- [#5482](https://github.com/blockscout/blockscout/pull/5482) - Fix for querying of the contract read functions - [#5455](https://github.com/blockscout/blockscout/pull/5455) - Fix unverified_smart_contract function: add md5 of bytecode to the changeset - [#5454](https://github.com/blockscout/blockscout/pull/5454) - Docker: Fix the qemu-x86_64 signal 11 error on Apple Silicon - [#5443](https://github.com/blockscout/blockscout/pull/5443) - Geth: display tx revert reason diff --git a/apps/block_scout_web/assets/js/lib/smart_contract/interact.js b/apps/block_scout_web/assets/js/lib/smart_contract/interact.js index d269be59c2d2..5ac91bc9cb23 100644 --- a/apps/block_scout_web/assets/js/lib/smart_contract/interact.js +++ b/apps/block_scout_web/assets/js/lib/smart_contract/interact.js @@ -4,22 +4,23 @@ import { compareChainIDs, formatError, formatTitleAndError, getContractABI, getC import BigNumber from 'bignumber.js' export const queryMethod = (isWalletEnabled, url, $methodId, args, type, functionName, $responseContainer) => { - let data = { + const data = { function_name: functionName, method_id: $methodId.val(), - type: type, - args + type: type } + + data.args_count = args.length + let i = args.length + + while (i--) { + data['arg_' + i] = args[i] + } + if (isWalletEnabled) { getCurrentAccountPromise(window.web3 && window.web3.currentProvider) .then((currentAccount) => { - data = { - function_name: functionName, - method_id: $methodId.val(), - type: type, - from: currentAccount, - args - } + data.from = currentAccount $.get(url, data, response => $responseContainer.html(response)) } ) diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/smart_contract_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/smart_contract_controller.ex index 621dd661cdf5..23201b96ad42 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/smart_contract_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/smart_contract_controller.ex @@ -105,8 +105,12 @@ defmodule BlockScoutWeb.SmartContractController do {:ok, _address} <- Chain.find_contract_address(address_hash, address_options, true) do contract_type = if params["type"] == "proxy", do: :proxy, else: :regular - # we should convert: %{"0" => _, "1" => _} to [_, _] - args = params["args"] |> convert_map_to_array() + {args_count, _} = Integer.parse(params["args_count"]) + + args = + if args_count < 1, + do: [], + else: for(x <- 0..(args_count - 1), do: params["arg_" <> to_string(x)] |> convert_map_to_array()) %{output: outputs, names: names} = if params["from"] do diff --git a/apps/block_scout_web/test/block_scout_web/controllers/smart_contract_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/smart_contract_controller_test.exs index 035868624b03..17148418896b 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/smart_contract_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/smart_contract_controller_test.exs @@ -250,6 +250,7 @@ defmodule BlockScoutWeb.SmartContractControllerTest do Address.checksum(smart_contract.address_hash), function_name: "get", method_id: "6d4ce63c", + args_count: 0, args: [] ) From ce03b85acdf6ed756d9ce494207406fa195e728f Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Wed, 6 Apr 2022 12:30:28 +0300 Subject: [PATCH 064/128] Deduplicate addresses and coin balances before inserting to the DB --- CHANGELOG.md | 1 + .../import/runner/address/coin_balances.ex | 5 ++- .../explorer/chain/import/runner/addresses.ex | 31 ++++++++++++++++--- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6081d902ac41..5c8b083dbf4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ - [#5455](https://github.com/blockscout/blockscout/pull/5455) - Fix unverified_smart_contract function: add md5 of bytecode to the changeset - [#5454](https://github.com/blockscout/blockscout/pull/5454) - Docker: Fix the qemu-x86_64 signal 11 error on Apple Silicon - [#5443](https://github.com/blockscout/blockscout/pull/5443) - Geth: display tx revert reason +- [#5420](https://github.com/blockscout/blockscout/pull/5420) - Deduplicate addresses and coin balances before inserting to the DB - [#5416](https://github.com/blockscout/blockscout/pull/5416) - Fix getsourcecode for EOA addresses - [#5411](https://github.com/blockscout/blockscout/pull/5411) - Fix character_not_in_repertoire error for tx revert reason - [#5410](https://github.com/blockscout/blockscout/pull/5410) - Handle exited realtime fetcher diff --git a/apps/explorer/lib/explorer/chain/import/runner/address/coin_balances.ex b/apps/explorer/lib/explorer/chain/import/runner/address/coin_balances.ex index ecc67cd9d447..f2967ec06a63 100644 --- a/apps/explorer/lib/explorer/chain/import/runner/address/coin_balances.ex +++ b/apps/explorer/lib/explorer/chain/import/runner/address/coin_balances.ex @@ -72,7 +72,10 @@ defmodule Explorer.Chain.Import.Runner.Address.CoinBalances do on_conflict = Map.get_lazy(options, :on_conflict, &default_on_conflict/0) # Enforce CoinBalance ShareLocks order (see docs: sharelocks.md) - ordered_changes_list = Enum.sort_by(changes_list, &{&1.address_hash, &1.block_number}) + ordered_changes_list = + changes_list + |> Enum.sort_by(&{&1.address_hash, &1.block_number}) + |> Enum.dedup() {:ok, _} = Import.insert_changes_list( diff --git a/apps/explorer/lib/explorer/chain/import/runner/addresses.ex b/apps/explorer/lib/explorer/chain/import/runner/addresses.ex index 71771239daa5..c62ae6d1236f 100644 --- a/apps/explorer/lib/explorer/chain/import/runner/addresses.ex +++ b/apps/explorer/lib/explorer/chain/import/runner/addresses.ex @@ -81,7 +81,19 @@ defmodule Explorer.Chain.Import.Runner.Addresses do on_conflict = Map.get_lazy(options, :on_conflict, &default_on_conflict/0) # Enforce Address ShareLocks order (see docs: sharelocks.md) - ordered_changes_list = sort_changes_list(changes_list) + ordered_changes_list = + changes_list + |> Enum.group_by(fn %{ + hash: hash + } -> + {hash} + end) + |> Enum.map(fn {_, grouped_addresses} -> + Enum.max_by(grouped_addresses, fn address -> + address_max_by(address) + end) + end) + |> Enum.sort_by(& &1.hash) Import.insert_changes_list( repo, @@ -95,6 +107,19 @@ defmodule Explorer.Chain.Import.Runner.Addresses do ) end + defp address_max_by(address) do + cond do + Map.has_key?(address, :address) -> + address.fetched_coin_balance_block_number + + Map.has_key?(address, :nonce) -> + address.nonce + + true -> + address + end + end + defp default_on_conflict do from(address in Address, update: [ @@ -139,10 +164,6 @@ defmodule Explorer.Chain.Import.Runner.Addresses do ) end - defp sort_changes_list(changes_list) do - Enum.sort_by(changes_list, & &1.hash) - end - defp update_transactions(repo, addresses, %{timeout: timeout, timestamps: timestamps}) do ordered_created_contract_hashes = addresses From 9c4984041dabd88d2ab0f50a0337ad47aa9ed580 Mon Sep 17 00:00:00 2001 From: nikitosing Date: Tue, 5 Apr 2022 01:28:46 +0300 Subject: [PATCH 065/128] Fix params encoding for read contracts methods --- CHANGELOG.md | 1 + .../assets/js/lib/smart_contract/common_helpers.js | 5 ++++- apps/explorer/lib/explorer/smart_contract/reader.ex | 7 +------ apps/explorer/test/explorer/smart_contract/reader_test.exs | 4 ++-- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e7457e1e1ff..fdea7caf5606 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ - [#5443](https://github.com/blockscout/blockscout/pull/5443) - Geth: display tx revert reason - [#5420](https://github.com/blockscout/blockscout/pull/5420) - Deduplicate addresses and coin balances before inserting to the DB - [#5416](https://github.com/blockscout/blockscout/pull/5416) - Fix getsourcecode for EOA addresses +- [#5413](https://github.com/blockscout/blockscout/pull/5413) - Fix params encoding for read contracts methods - [#5411](https://github.com/blockscout/blockscout/pull/5411) - Fix character_not_in_repertoire error for tx revert reason - [#5410](https://github.com/blockscout/blockscout/pull/5410) - Handle exited realtime fetcher - [#5383](https://github.com/blockscout/blockscout/pull/5383) - Fix reload transactions button diff --git a/apps/block_scout_web/assets/js/lib/smart_contract/common_helpers.js b/apps/block_scout_web/assets/js/lib/smart_contract/common_helpers.js index 80432a5bc8c6..ecb3326a35d3 100644 --- a/apps/block_scout_web/assets/js/lib/smart_contract/common_helpers.js +++ b/apps/block_scout_web/assets/js/lib/smart_contract/common_helpers.js @@ -278,7 +278,10 @@ function replaceSpaces (value, type, components) { }) .join(',') } else { - return value.trim() + if (typeof value.trim === 'function') { + return value.trim() + } + return value } } diff --git a/apps/explorer/lib/explorer/smart_contract/reader.ex b/apps/explorer/lib/explorer/smart_contract/reader.ex index 89d5a7d40a42..b9f4410a1b56 100644 --- a/apps/explorer/lib/explorer/smart_contract/reader.ex +++ b/apps/explorer/lib/explorer/smart_contract/reader.ex @@ -562,12 +562,7 @@ defmodule Explorer.SmartContract.Reader do case response do {integer, ""} -> - hex_encoding = - integer - |> :binary.encode_unsigned() - |> Base.encode16(case: :lower) - - "0x" <> hex_encoding + integer _ -> item diff --git a/apps/explorer/test/explorer/smart_contract/reader_test.exs b/apps/explorer/test/explorer/smart_contract/reader_test.exs index 3b2e7d147129..f2b555331306 100644 --- a/apps/explorer/test/explorer/smart_contract/reader_test.exs +++ b/apps/explorer/test/explorer/smart_contract/reader_test.exs @@ -286,12 +286,12 @@ defmodule Explorer.SmartContract.ReaderTest do describe "normalize_args/1" do test "converts argument when is a number" do - assert ["0x00"] = Reader.normalize_args(["0"]) + assert [0] = Reader.normalize_args(["0"]) assert ["0x798465571ae21a184a272f044f991ad1d5f87a3f"] = Reader.normalize_args(["0x798465571ae21a184a272f044f991ad1d5f87a3f"]) - assert ["0x7b"] = Reader.normalize_args(["123"]) + assert [123] = Reader.normalize_args(["123"]) end test "converts argument when is a boolean" do From f04f8f151b745abf0f3a25cf1d9d6249f7562a1e Mon Sep 17 00:00:00 2001 From: nikitosing Date: Tue, 5 Apr 2022 18:19:41 +0300 Subject: [PATCH 066/128] Fix structure array encoding --- .../js/lib/smart_contract/common_helpers.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/block_scout_web/assets/js/lib/smart_contract/common_helpers.js b/apps/block_scout_web/assets/js/lib/smart_contract/common_helpers.js index ecb3326a35d3..2ffeaf83de67 100644 --- a/apps/block_scout_web/assets/js/lib/smart_contract/common_helpers.js +++ b/apps/block_scout_web/assets/js/lib/smart_contract/common_helpers.js @@ -266,9 +266,9 @@ function isNonSpaceInputType (inputType) { } function replaceSpaces (value, type, components) { - if (isNonSpaceInputType(type)) { + if (isNonSpaceInputType(type) && isFunction(value.replace)) { return value.replace(/\s/g, '') - } else if (isTupleInputType(type)) { + } else if (isTupleInputType(type) && isFunction(value.split)) { return value .split(',') .map((itemValue, itemIndex) => { @@ -287,12 +287,13 @@ function replaceSpaces (value, type, components) { function replaceDoubleQuotes (value, type, components) { if (isAddressInputType(type) || isUintInputType(type) || isStringInputType(type) || isBytesInputType(type)) { - if (typeof value.replaceAll === 'function') { + if (isFunction(value.replaceAll)) { return value.replaceAll('"', '') - } else { + } else if (isFunction(value.replace)) { return value.replace(/"/g, '') } - } else if (isTupleInputType(type)) { + return value + } else if (isTupleInputType(type) && isFunction(value.split)) { return value .split(',') .map((itemValue, itemIndex) => { @@ -305,3 +306,7 @@ function replaceDoubleQuotes (value, type, components) { return value } } + +function isFunction (param) { + return typeof param === 'function' +} From a58f3d57994ca894158495dd5ba04fb789368bfa Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Wed, 27 Apr 2022 12:56:53 +0300 Subject: [PATCH 067/128] Extend TRACE_FIRST_BLOCK env var to geth variant --- CHANGELOG.md | 1 + apps/block_scout_web/assets/package-lock.json | 5 ++-- apps/ethereum_jsonrpc/lib/ethereum_jsonrpc.ex | 25 ++++++++----------- apps/explorer/lib/explorer/chain.ex | 3 ++- .../indexer/fetcher/internal_transaction.ex | 17 +++++++------ 5 files changed, 26 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fdea7caf5606..0b25857c9817 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - [#5268](https://github.com/blockscout/blockscout/pull/5268), [#5313](https://github.com/blockscout/blockscout/pull/5313) - Contract names display improvement ### Fixes +- [#5504](https://github.com/blockscout/blockscout/pull/5504) - Extend TRACE_FIRST_BLOCK env var to geth variant - [#5488](https://github.com/blockscout/blockscout/pull/5488) - Split long contract output to multiple lines - [#5487](https://github.com/blockscout/blockscout/pull/5487) - Fix array displaying in decoded constructor args - [#5482](https://github.com/blockscout/blockscout/pull/5482) - Fix for querying of the contract read functions diff --git a/apps/block_scout_web/assets/package-lock.json b/apps/block_scout_web/assets/package-lock.json index 2512c4aac119..13898d4dd733 100644 --- a/apps/block_scout_web/assets/package-lock.json +++ b/apps/block_scout_web/assets/package-lock.json @@ -95,10 +95,11 @@ } }, "../../../deps/phoenix": { - "version": "0.0.1" + "version": "1.5.13", + "license": "MIT" }, "../../../deps/phoenix_html": { - "version": "0.0.1" + "version": "2.14.3" }, "node_modules/@babel/code-frame": { "version": "7.16.7", diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc.ex index e42aad256e77..d3a7ddfe9542 100644 --- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc.ex +++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc.ex @@ -219,13 +219,7 @@ defmodule EthereumJSONRPC do @spec fetch_beneficiaries([block_number], json_rpc_named_arguments) :: {:ok, FetchedBeneficiaries.t()} | {:error, reason :: term} | :ignore def fetch_beneficiaries(block_numbers, json_rpc_named_arguments) when is_list(block_numbers) do - min_block = trace_first_block_to_fetch() - - filtered_block_numbers = - block_numbers - |> Enum.filter(fn block_number -> - block_number >= min_block - end) + filtered_block_numbers = block_numbers_in_range(block_numbers) Keyword.fetch!(json_rpc_named_arguments, :variant).fetch_beneficiaries( filtered_block_numbers, @@ -310,13 +304,7 @@ defmodule EthereumJSONRPC do Fetches internal transactions for entire blocks from variant API. """ def fetch_block_internal_transactions(block_numbers, json_rpc_named_arguments) when is_list(block_numbers) do - min_block = trace_first_block_to_fetch() - - filtered_block_numbers = - block_numbers - |> Enum.filter(fn block_number -> - block_number >= min_block - end) + filtered_block_numbers = block_numbers_in_range(block_numbers) Keyword.fetch!(json_rpc_named_arguments, :variant).fetch_block_internal_transactions( filtered_block_numbers, @@ -324,6 +312,15 @@ defmodule EthereumJSONRPC do ) end + def block_numbers_in_range(block_numbers) do + min_block = trace_first_block_to_fetch() + + block_numbers + |> Enum.filter(fn block_number -> + block_number >= min_block + end) + end + @doc """ Retrieves traces from variant API. """ diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index 559ae110995d..5d9d7aa11330 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -7028,7 +7028,8 @@ defmodule Explorer.Chain do if transaction_index == 0 do 0 else - {:ok, traces} = fetch_block_internal_transactions([block_number], json_rpc_named_arguments) + filtered_block_numbers = EthereumJSONRPC.block_numbers_in_range([block_number]) + {:ok, traces} = fetch_block_internal_transactions(filtered_block_numbers, json_rpc_named_arguments) sorted_traces = traces diff --git a/apps/indexer/lib/indexer/fetcher/internal_transaction.ex b/apps/indexer/lib/indexer/fetcher/internal_transaction.ex index 6a112dfeb68d..13716a88c414 100644 --- a/apps/indexer/lib/indexer/fetcher/internal_transaction.ex +++ b/apps/indexer/lib/indexer/fetcher/internal_transaction.ex @@ -98,9 +98,10 @@ defmodule Indexer.Fetcher.InternalTransaction do ) def run(block_numbers, json_rpc_named_arguments) do unique_numbers = Enum.uniq(block_numbers) + filtered_unique_numbers = EthereumJSONRPC.block_numbers_in_range(unique_numbers) - unique_numbers_count = Enum.count(unique_numbers) - Logger.metadata(count: unique_numbers_count) + filtered_unique_numbers_count = Enum.count(filtered_unique_numbers) + Logger.metadata(count: filtered_unique_numbers_count) Logger.debug("fetching internal transactions for blocks") @@ -108,14 +109,14 @@ defmodule Indexer.Fetcher.InternalTransaction do |> Keyword.fetch!(:variant) |> case do EthereumJSONRPC.Parity -> - EthereumJSONRPC.fetch_block_internal_transactions(unique_numbers, json_rpc_named_arguments) + EthereumJSONRPC.fetch_block_internal_transactions(filtered_unique_numbers, json_rpc_named_arguments) EthereumJSONRPC.Besu -> - EthereumJSONRPC.fetch_block_internal_transactions(unique_numbers, json_rpc_named_arguments) + EthereumJSONRPC.fetch_block_internal_transactions(filtered_unique_numbers, json_rpc_named_arguments) _ -> try do - fetch_block_internal_transactions_by_transactions(unique_numbers, json_rpc_named_arguments) + fetch_block_internal_transactions_by_transactions(filtered_unique_numbers, json_rpc_named_arguments) rescue error -> {:error, error} @@ -123,15 +124,15 @@ defmodule Indexer.Fetcher.InternalTransaction do end |> case do {:ok, internal_transactions_params} -> - import_internal_transaction(internal_transactions_params, unique_numbers) + import_internal_transaction(internal_transactions_params, filtered_unique_numbers) {:error, reason} -> Logger.error(fn -> ["failed to fetch internal transactions for blocks: ", inspect(reason)] end, - error_count: unique_numbers_count + error_count: filtered_unique_numbers_count ) # re-queue the de-duped entries - {:retry, unique_numbers} + {:retry, filtered_unique_numbers} :ignore -> :ok From 77e14683e91b05a44d80404f556f0981223edd20 Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Wed, 27 Apr 2022 13:52:55 +0300 Subject: [PATCH 068/128] Manage debug_traceTransaction JSON RPC method timeout --- CHANGELOG.md | 1 + apps/ethereum_jsonrpc/config/config.exs | 3 +++ apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth.ex | 9 ++++++++- docker/Makefile | 3 +++ 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fdea7caf5606..aeab96a1c0e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## Current ### Features +- [#5505](https://github.com/blockscout/blockscout/pull/5505) - Manage debug_traceTransaction JSON RPC method timeout - [#5491](https://github.com/blockscout/blockscout/pull/5491) - Sequential blocks broadcast on the main page - [#5312](https://github.com/blockscout/blockscout/pull/5312) - Add OpenZeppelin proxy storage slot - [#5302](https://github.com/blockscout/blockscout/pull/5302) - Add specific tx receipt fields for the GoQuorum client diff --git a/apps/ethereum_jsonrpc/config/config.exs b/apps/ethereum_jsonrpc/config/config.exs index 251b7c7e3a79..e85965204da8 100644 --- a/apps/ethereum_jsonrpc/config/config.exs +++ b/apps/ethereum_jsonrpc/config/config.exs @@ -26,6 +26,9 @@ config :ethereum_jsonrpc, EthereumJSONRPC.Tracer, adapter: SpandexDatadog.Adapter, trace_key: :blockscout +debug_trace_transaction_timeout = System.get_env("ETHEREUM_JSONRPC_DEBUG_TRACE_TRANSACTION_TIMEOUT", "5s") +config :ethereum_jsonrpc, EthereumJSONRPC.Geth, debug_trace_transaction_timeout: debug_trace_transaction_timeout + config :logger, :ethereum_jsonrpc, # keep synced with `config/config.exs` format: "$dateT$time $metadata[$level] $message\n", diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth.ex index 05e32348f24d..b067ed1f1cc8 100644 --- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth.ex +++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth.ex @@ -89,7 +89,14 @@ defmodule EthereumJSONRPC.Geth do @tracer File.read!(@tracer_path) defp debug_trace_transaction_request(%{id: id, hash_data: hash_data}) do - request(%{id: id, method: "debug_traceTransaction", params: [hash_data, %{tracer: @tracer}]}) + debug_trace_transaction_timeout = + Application.get_env(:ethereum_jsonrpc, __MODULE__)[:debug_trace_transaction_timeout] + + request(%{ + id: id, + method: "debug_traceTransaction", + params: [hash_data, %{tracer: @tracer, timeout: debug_trace_transaction_timeout}] + }) end defp debug_trace_transaction_responses_to_internal_transactions_params( diff --git a/docker/Makefile b/docker/Makefile index 86cae05a182d..a6ddcfa1913a 100644 --- a/docker/Makefile +++ b/docker/Makefile @@ -397,6 +397,9 @@ endif ifdef INDEXER_MEMORY_LIMIT BLOCKSCOUT_CONTAINER_PARAMS += -e 'INDEXER_MEMORY_LIMIT=$(INDEXER_MEMORY_LIMIT)' endif +ifdef ETHEREUM_JSONRPC_DEBUG_TRACE_TRANSACTION_TIMEOUT + BLOCKSCOUT_CONTAINER_PARAMS += -e 'ETHEREUM_JSONRPC_DEBUG_TRACE_TRANSACTION_TIMEOUT=$(ETHEREUM_JSONRPC_DEBUG_TRACE_TRANSACTION_TIMEOUT)' +endif HAS_BLOCKSCOUT_IMAGE := $(shell docker images | grep -sw "${BS_CONTAINER_IMAGE} ") build: From b107a531edcf02c40adfd137f4fb7b87653afd03 Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Wed, 27 Apr 2022 15:01:46 +0300 Subject: [PATCH 069/128] Refactor config --- CHANGELOG.md | 1 + apps/block_scout_web/config/config.exs | 15 +++--- apps/explorer/config/config.exs | 49 +++++++++++-------- apps/indexer/config/config.exs | 26 +++++----- .../indexer/fetcher/coin_balance_on_demand.ex | 3 +- .../fetcher/token_balance_on_demand.ex | 3 +- 6 files changed, 55 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fdea7caf5606..23db7715ffcf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ - [#5239](https://github.com/blockscout/blockscout/pull/5239) - Add accounting for block rewards in `getblockreward` api method ### Chore +- [#5506](https://github.com/blockscout/blockscout/pull/5506) - Refactor config files - [#5480](https://github.com/blockscout/blockscout/pull/5480) - Remove duplicate of balances_params_to_address_params function - [#5473](https://github.com/blockscout/blockscout/pull/5473) - Refactor daily coin balances fetcher - [#5458](https://github.com/blockscout/blockscout/pull/5458) - Decrease min safe polling period for realtime fetcher diff --git a/apps/block_scout_web/config/config.exs b/apps/block_scout_web/config/config.exs index 8392cfdda8a8..9fc2c0ef2fc8 100644 --- a/apps/block_scout_web/config/config.exs +++ b/apps/block_scout_web/config/config.exs @@ -55,31 +55,34 @@ config :block_scout_web, re_captcha_client_key: System.get_env("RE_CAPTCHA_CLIENT_KEY", nil), admin_panel_enabled: System.get_env("ADMIN_PANEL_ENABLED", "") == "true" +default_api_rate_limit = 50 +default_api_rate_limit_str = Integer.to_string(default_api_rate_limit) + global_api_rate_limit_value = "API_RATE_LIMIT" - |> System.get_env("50") + |> System.get_env(default_api_rate_limit_str) |> Integer.parse() |> case do {integer, ""} -> integer - _ -> 50 + _ -> default_api_rate_limit end api_rate_limit_by_key_value = "API_RATE_LIMIT_BY_KEY" - |> System.get_env("50") + |> System.get_env(default_api_rate_limit_str) |> Integer.parse() |> case do {integer, ""} -> integer - _ -> 50 + _ -> default_api_rate_limit end api_rate_limit_by_ip_value = "API_RATE_LIMIT_BY_IP" - |> System.get_env("50") + |> System.get_env(default_api_rate_limit_str) |> Integer.parse() |> case do {integer, ""} -> integer - _ -> 50 + _ -> default_api_rate_limit end config :block_scout_web, :api_rate_limit, diff --git a/apps/explorer/config/config.exs b/apps/explorer/config/config.exs index c8986bfab680..2ce8c0c4eac2 100644 --- a/apps/explorer/config/config.exs +++ b/apps/explorer/config/config.exs @@ -5,6 +5,9 @@ # is restricted to this project. import Config +disable_indexer = System.get_env("DISABLE_INDEXER") +disable_webapp = System.get_env("DISABLE_WEBAPP") + # General application configuration config :explorer, ecto_repos: [Explorer.Repo], @@ -18,7 +21,7 @@ config :explorer, if(System.get_env("UNCLES_IN_AVERAGE_BLOCK_TIME") == "true", do: true, else: false), healthy_blocks_period: System.get_env("HEALTHY_BLOCKS_PERIOD") || :timer.minutes(5), realtime_events_sender: - if(System.get_env("DISABLE_WEBAPP") != "true", + if(disable_webapp != "true", do: Explorer.Chain.Events.SimpleSender, else: Explorer.Chain.Events.DBSender ) @@ -29,7 +32,7 @@ config :explorer, Explorer.Counters.AverageBlockTime, config :explorer, Explorer.Chain.Events.Listener, enabled: - if(System.get_env("DISABLE_WEBAPP") == "true" && System.get_env("DISABLE_INDEXER") == "true", + if(disable_webapp == "true" && disable_indexer == "true", do: false, else: true ) @@ -42,8 +45,8 @@ config :explorer, Explorer.ChainSpec.GenesisData, config :explorer, Explorer.Chain.Cache.BlockNumber, enabled: true, - ttl_check_interval: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(1), else: false), - global_ttl: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(5)) + ttl_check_interval: if(disable_indexer == "true", do: :timer.seconds(1), else: false), + global_ttl: if(disable_indexer == "true", do: :timer.seconds(5)) address_sum_global_ttl = "CACHE_ADDRESS_SUM_PERIOD" @@ -64,9 +67,11 @@ config :explorer, Explorer.Chain.Cache.AddressSumMinusBurnt, ttl_check_interval: :timer.seconds(1), global_ttl: address_sum_global_ttl +cache_address_with_balances_update_interval = System.get_env("CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL") + balances_update_interval = - if System.get_env("CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL") do - case Integer.parse(System.get_env("CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL")) do + if cache_address_with_balances_update_interval do + case Integer.parse(cache_address_with_balances_update_interval) do {integer, ""} -> integer _ -> nil end @@ -121,9 +126,11 @@ config :explorer, Explorer.Counters.BlockPriorityFeeCounter, config :explorer, Explorer.Chain.Cache.GasUsage, enabled: System.get_env("CACHE_ENABLE_TOTAL_GAS_USAGE_COUNTER") == "true" +cache_bridge_market_cap_update_interval = System.get_env("CACHE_BRIDGE_MARKET_CAP_UPDATE_INTERVAL") + bridge_market_cap_update_interval = - if System.get_env("CACHE_BRIDGE_MARKET_CAP_UPDATE_INTERVAL") do - case Integer.parse(System.get_env("CACHE_BRIDGE_MARKET_CAP_UPDATE_INTERVAL")) do + if cache_bridge_market_cap_update_interval do + case Integer.parse(cache_bridge_market_cap_update_interval) do {integer, ""} -> integer _ -> nil end @@ -141,7 +148,7 @@ config :explorer, Explorer.KnownTokens, enabled: System.get_env("DISABLE_KNOWN_T config :explorer, Explorer.Integrations.EctoLogger, query_time_ms_threshold: :timer.seconds(2) -config :explorer, Explorer.Market.History.Cataloger, enabled: System.get_env("DISABLE_INDEXER") != "true" +config :explorer, Explorer.Market.History.Cataloger, enabled: disable_indexer != "true" config :explorer, Explorer.Chain.Cache.MinMissingBlockNumber, enabled: System.get_env("DISABLE_WRITE_API") != "true" @@ -182,7 +189,7 @@ if System.get_env("METADATA_CONTRACT") && System.get_env("VALIDATORS_CONTRACT") metadata_contract_address: System.get_env("METADATA_CONTRACT"), validators_contract_address: System.get_env("VALIDATORS_CONTRACT") - config :explorer, Explorer.Validator.MetadataProcessor, enabled: System.get_env("DISABLE_INDEXER") != "true" + config :explorer, Explorer.Validator.MetadataProcessor, enabled: disable_indexer != "true" else config :explorer, Explorer.Validator.MetadataProcessor, enabled: false end @@ -191,10 +198,12 @@ config :explorer, Explorer.Chain.Block.Reward, validators_contract_address: System.get_env("VALIDATORS_CONTRACT"), keys_manager_contract_address: System.get_env("KEYS_MANAGER_CONTRACT") -if System.get_env("POS_STAKING_CONTRACT") do +pos_staking_contract = System.get_env("POS_STAKING_CONTRACT") + +if pos_staking_contract do config :explorer, Explorer.Staking.ContractState, enabled: true, - staking_contract_address: System.get_env("POS_STAKING_CONTRACT"), + staking_contract_address: pos_staking_contract, eth_subscribe_max_delay: System.get_env("POS_ETH_SUBSCRIBE_MAX_DELAY", "60"), eth_blocknumber_pull_interval: System.get_env("POS_ETH_BLOCKNUMBER_PULL_INTERVAL", "500") else @@ -234,20 +243,20 @@ config :spandex_ecto, SpandexEcto.EctoLogger, otp_app: :explorer config :explorer, Explorer.Chain.Cache.Blocks, - ttl_check_interval: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(1), else: false), - global_ttl: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(5)) + ttl_check_interval: if(disable_indexer == "true", do: :timer.seconds(1), else: false), + global_ttl: if(disable_indexer == "true", do: :timer.seconds(5)) config :explorer, Explorer.Chain.Cache.Transactions, - ttl_check_interval: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(1), else: false), - global_ttl: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(5)) + ttl_check_interval: if(disable_indexer == "true", do: :timer.seconds(1), else: false), + global_ttl: if(disable_indexer == "true", do: :timer.seconds(5)) config :explorer, Explorer.Chain.Cache.Accounts, - ttl_check_interval: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(1), else: false), - global_ttl: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(5)) + ttl_check_interval: if(disable_indexer == "true", do: :timer.seconds(1), else: false), + global_ttl: if(disable_indexer == "true", do: :timer.seconds(5)) config :explorer, Explorer.Chain.Cache.Uncles, - ttl_check_interval: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(1), else: false), - global_ttl: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(5)) + ttl_check_interval: if(disable_indexer == "true", do: :timer.seconds(1), else: false), + global_ttl: if(disable_indexer == "true", do: :timer.seconds(5)) config :explorer, Explorer.ThirdPartyIntegrations.Sourcify, server_url: System.get_env("SOURCIFY_SERVER_URL") || "https://sourcify.dev/server", diff --git a/apps/indexer/config/config.exs b/apps/indexer/config/config.exs index d543da222589..80330b902257 100644 --- a/apps/indexer/config/config.exs +++ b/apps/indexer/config/config.exs @@ -41,26 +41,24 @@ config :indexer, Indexer.Fetcher.PendingTransaction.Supervisor, System.get_env("ETHEREUM_JSONRPC_VARIANT") == "besu" || System.get_env("INDEXER_DISABLE_PENDING_TRANSACTIONS_FETCHER", "false") == "true" +token_balance_on_demand_fetcher_threshold_minutes = System.get_env("TOKEN_BALANCE_ON_DEMAND_FETCHER_THRESHOLD_MINUTES") + token_balance_on_demand_fetcher_threshold = - if System.get_env("TOKEN_BALANCE_ON_DEMAND_FETCHER_THRESHOLD_MINUTES") do - case Integer.parse(System.get_env("TOKEN_BALANCE_ON_DEMAND_FETCHER_THRESHOLD_MINUTES")) do - {integer, ""} -> integer - _ -> 60 - end - else - 60 + case token_balance_on_demand_fetcher_threshold_minutes && + Integer.parse(token_balance_on_demand_fetcher_threshold_minutes) do + {integer, ""} -> integer + _ -> 60 end config :indexer, Indexer.Fetcher.TokenBalanceOnDemand, threshold: token_balance_on_demand_fetcher_threshold +coin_balance_on_demand_fetcher_threshold_minutes = System.get_env("COIN_BALANCE_ON_DEMAND_FETCHER_THRESHOLD_MINUTES") + coin_balance_on_demand_fetcher_threshold = - if System.get_env("COIN_BALANCE_ON_DEMAND_FETCHER_THRESHOLD_MINUTES") do - case Integer.parse(System.get_env("COIN_BALANCE_ON_DEMAND_FETCHER_THRESHOLD_MINUTES")) do - {integer, ""} -> integer - _ -> 60 - end - else - 60 + case coin_balance_on_demand_fetcher_threshold_minutes && + Integer.parse(coin_balance_on_demand_fetcher_threshold_minutes) do + {integer, ""} -> integer + _ -> 60 end config :indexer, Indexer.Fetcher.CoinBalanceOnDemand, threshold: coin_balance_on_demand_fetcher_threshold diff --git a/apps/indexer/lib/indexer/fetcher/coin_balance_on_demand.ex b/apps/indexer/lib/indexer/fetcher/coin_balance_on_demand.ex index e7989a027e86..ac02a8f2d288 100644 --- a/apps/indexer/lib/indexer/fetcher/coin_balance_on_demand.ex +++ b/apps/indexer/lib/indexer/fetcher/coin_balance_on_demand.ex @@ -230,7 +230,8 @@ defmodule Indexer.Fetcher.CoinBalanceOnDemand do if average_block_time == 0 do {:error, :empty_database} else - block_number - div(:timer.minutes(Application.get_env(:indexer, __MODULE__)[:threshold]), average_block_time) + threshold = Application.get_env(:indexer, __MODULE__)[:threshold] + block_number - div(:timer.minutes(threshold), average_block_time) end end end diff --git a/apps/indexer/lib/indexer/fetcher/token_balance_on_demand.ex b/apps/indexer/lib/indexer/fetcher/token_balance_on_demand.ex index 620586c0ad0e..c63397736d03 100644 --- a/apps/indexer/lib/indexer/fetcher/token_balance_on_demand.ex +++ b/apps/indexer/lib/indexer/fetcher/token_balance_on_demand.ex @@ -104,7 +104,8 @@ defmodule Indexer.Fetcher.TokenBalanceOnDemand do if average_block_time == 0 do {:error, :empty_database} else - block_number - div(:timer.minutes(Application.get_env(:indexer, __MODULE__)[:threshold]), average_block_time) + threshold = Application.get_env(:indexer, __MODULE__)[:threshold] + block_number - div(:timer.minutes(threshold), average_block_time) end end end From f4a5275e2054eb1b9180cc1b3a3d3a73bf3f5fe0 Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Wed, 27 Apr 2022 18:26:35 +0300 Subject: [PATCH 070/128] Hide indexing banner if we fetched internal transactions from TRACE_FIRST_BLOCK --- CHANGELOG.md | 1 + apps/explorer/lib/explorer/chain.ex | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b2d76424c571..997637ce92aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - [#5268](https://github.com/blockscout/blockscout/pull/5268), [#5313](https://github.com/blockscout/blockscout/pull/5313) - Contract names display improvement ### Fixes +- [#5508](https://github.com/blockscout/blockscout/pull/5508) - Hide indexing banner if we fetched internal transactions from TRACE_FIRST_BLOCK - [#5504](https://github.com/blockscout/blockscout/pull/5504) - Extend TRACE_FIRST_BLOCK env var to geth variant - [#5488](https://github.com/blockscout/blockscout/pull/5488) - Split long contract output to multiple lines - [#5487](https://github.com/blockscout/blockscout/pull/5487) - Fix array displaying in decoded constructor args diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index 5d9d7aa11330..ad1f79af3e43 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -1146,6 +1146,11 @@ defmodule Explorer.Chain do else with {:transactions_exist, true} <- {:transactions_exist, Repo.exists?(Transaction)}, min_block_number when not is_nil(min_block_number) <- Repo.aggregate(Transaction, :min, :block_number) do + min_block_number = + min_block_number + |> Decimal.max(EthereumJSONRPC.first_block_to_fetch(:trace_first_block)) + |> Decimal.to_integer() + query = from( b in Block, From 58236eebb9c9dcd4875845c7c149130e8f96185f Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Thu, 28 Apr 2022 12:08:43 +0300 Subject: [PATCH 071/128] Do not fill pending blocks ops with block numbers below TRACE_FIRST_BLOCK --- CHANGELOG.md | 1 + apps/ethereum_jsonrpc/lib/ethereum_jsonrpc.ex | 6 +-- .../explorer/chain/import/runner/blocks.ex | 38 +++++++++++++++++-- .../import/runner/internal_transactions.ex | 6 +-- 4 files changed, 37 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 997637ce92aa..ed878652d277 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - [#5268](https://github.com/blockscout/blockscout/pull/5268), [#5313](https://github.com/blockscout/blockscout/pull/5313) - Contract names display improvement ### Fixes +- [#5513](https://github.com/blockscout/blockscout/pull/5513) - Do not fill pending blocks ops with block numbers below TRACE_FIRST_BLOCK - [#5508](https://github.com/blockscout/blockscout/pull/5508) - Hide indexing banner if we fetched internal transactions from TRACE_FIRST_BLOCK - [#5504](https://github.com/blockscout/blockscout/pull/5504) - Extend TRACE_FIRST_BLOCK env var to geth variant - [#5488](https://github.com/blockscout/blockscout/pull/5488) - Split long contract output to multiple lines diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc.ex index d3a7ddfe9542..ab6399f93061 100644 --- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc.ex +++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc.ex @@ -313,7 +313,7 @@ defmodule EthereumJSONRPC do end def block_numbers_in_range(block_numbers) do - min_block = trace_first_block_to_fetch() + min_block = first_block_to_fetch(:trace_first_block) block_numbers |> Enum.filter(fn block_number -> @@ -485,10 +485,6 @@ defmodule EthereumJSONRPC do end end - defp trace_first_block_to_fetch do - first_block_to_fetch(:trace_first_block) - end - def first_block_to_fetch(config) do string_value = Application.get_env(:indexer, config) diff --git a/apps/explorer/lib/explorer/chain/import/runner/blocks.ex b/apps/explorer/lib/explorer/chain/import/runner/blocks.ex index a4b68d12c4ff..98e88de110b2 100644 --- a/apps/explorer/lib/explorer/chain/import/runner/blocks.ex +++ b/apps/explorer/lib/explorer/chain/import/runner/blocks.ex @@ -46,19 +46,42 @@ defmodule Explorer.Chain.Import.Runner.Blocks do |> Map.put(:timestamps, timestamps) hashes = Enum.map(changes_list, & &1.hash) + + minimal_block_height = trace_minimal_block_height() + + hashes_for_pending_block_operations = + if minimal_block_height > 0 do + changes_list + |> Enum.filter(&(&1.number >= minimal_block_height)) + |> Enum.map(& &1.hash) + else + hashes + end + consensus_block_numbers = consensus_block_numbers(changes_list) # Enforce ShareLocks tables order (see docs: sharelocks.md) multi |> Multi.run(:lose_consensus, fn repo, _ -> - lose_consensus(repo, hashes, consensus_block_numbers, changes_list, insert_options) + {:ok, nonconsensus_items} = lose_consensus(repo, hashes, consensus_block_numbers, changes_list, insert_options) + + nonconsensus_hashes = + if minimal_block_height > 0 do + nonconsensus_items + |> Enum.filter(fn {number, _hash} -> number >= minimal_block_height end) + |> Enum.map(fn {_number, hash} -> hash end) + else + hashes + end + + {:ok, nonconsensus_hashes} end) |> Multi.run(:blocks, fn repo, _ -> # Note, needs to be executed after `lose_consensus` for lock acquisition insert(repo, changes_list, insert_options) end) |> Multi.run(:new_pending_operations, fn repo, %{lose_consensus: nonconsensus_hashes} -> - new_pending_operations(repo, nonconsensus_hashes, hashes, insert_options) + new_pending_operations(repo, nonconsensus_hashes, hashes_for_pending_block_operations, insert_options) end) |> Multi.run(:uncle_fetched_block_second_degree_relations, fn repo, _ -> update_block_second_degree_relations(repo, hashes, %{ @@ -298,7 +321,7 @@ defmodule Explorer.Chain.Import.Runner.Blocks do on: block.hash == s.hash, # we don't want to remove consensus from blocks that will be upserted where: block.hash not in ^hashes, - select: block.hash + select: {block.number, block.hash} ), [set: [consensus: false, updated_at: updated_at]], timeout: timeout @@ -319,7 +342,14 @@ defmodule Explorer.Chain.Import.Runner.Blocks do lose_consensus(ExplorerRepo, [], block_numbers, [], opts) end - defp new_pending_operations(repo, nonconsensus_hashes, hashes, %{timeout: timeout, timestamps: timestamps}) do + defp trace_minimal_block_height do + EthereumJSONRPC.first_block_to_fetch(:trace_first_block) + end + + defp new_pending_operations(repo, nonconsensus_hashes, hashes, %{ + timeout: timeout, + timestamps: timestamps + }) do if Application.get_env(:explorer, :json_rpc_named_arguments)[:variant] == EthereumJSONRPC.RSK do {:ok, []} else diff --git a/apps/explorer/lib/explorer/chain/import/runner/internal_transactions.ex b/apps/explorer/lib/explorer/chain/import/runner/internal_transactions.ex index 1286825e8690..55189bacb168 100644 --- a/apps/explorer/lib/explorer/chain/import/runner/internal_transactions.ex +++ b/apps/explorer/lib/explorer/chain/import/runner/internal_transactions.ex @@ -609,7 +609,7 @@ defmodule Explorer.Chain.Import.Runner.InternalTransactions do end defp remove_consensus_of_invalid_blocks(repo, invalid_block_numbers) do - minimal_block = first_block_to_fetch() + minimal_block = EthereumJSONRPC.first_block_to_fetch(:trace_first_block) if Enum.count(invalid_block_numbers) > 0 do update_query = @@ -643,10 +643,6 @@ defmodule Explorer.Chain.Import.Runner.InternalTransactions do end end - def first_block_to_fetch do - EthereumJSONRPC.first_block_to_fetch(:trace_first_block) - end - def update_pending_blocks_status(repo, pending_hashes, invalid_block_hashes) do valid_block_hashes = pending_hashes From b8aa5d865698d2b7f3138650c058e307f10574e0 Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Thu, 28 Apr 2022 13:47:37 +0300 Subject: [PATCH 072/128] Set localization for "ETH" in Dockerfile in addition to "Ether" --- docker/Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docker/Dockerfile b/docker/Dockerfile index 82a6de93ae40..23e2a1182723 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -41,6 +41,8 @@ RUN if [ "$COIN" != "" ]; then \ sed -i s/"POA"/"${COIN}"/g apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po; \ sed -i "/msgid \"Ether\"/{n;s/msgstr \"\"/msgstr \"${COIN}\"/g}" apps/block_scout_web/priv/gettext/default.pot; \ sed -i "/msgid \"Ether\"/{n;s/msgstr \"\"/msgstr \"${COIN}\"/g}" apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po; \ + sed -i "/msgid \"ETH\"/{n;s/msgstr \"\"/msgstr \"${COIN}\"/g}" apps/block_scout_web/priv/gettext/default.pot; \ + sed -i "/msgid \"ETH\"/{n;s/msgstr \"\"/msgstr \"${COIN}\"/g}" apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po; \ fi # Run forderground build and phoenix digest From e334c96ce2ebb63014ed81ef70357002a80e5d88 Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Fri, 29 Apr 2022 18:16:46 +0300 Subject: [PATCH 073/128] Improve stability of ContractState module --- CHANGELOG.md | 1 + .../lib/explorer/staking/contract_state.ex | 115 ++++++++++-------- 2 files changed, 65 insertions(+), 51 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed878652d277..d46f034619a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - [#5268](https://github.com/blockscout/blockscout/pull/5268), [#5313](https://github.com/blockscout/blockscout/pull/5313) - Contract names display improvement ### Fixes +- [#5524](https://github.com/blockscout/blockscout/pull/5524) - ContractState module resistance to unresponsive archive node - [#5513](https://github.com/blockscout/blockscout/pull/5513) - Do not fill pending blocks ops with block numbers below TRACE_FIRST_BLOCK - [#5508](https://github.com/blockscout/blockscout/pull/5508) - Hide indexing banner if we fetched internal transactions from TRACE_FIRST_BLOCK - [#5504](https://github.com/blockscout/blockscout/pull/5504) - Extend TRACE_FIRST_BLOCK env var to geth variant diff --git a/apps/explorer/lib/explorer/staking/contract_state.ex b/apps/explorer/lib/explorer/staking/contract_state.ex index 7f75551adedc..ab1ede8f88a8 100644 --- a/apps/explorer/lib/explorer/staking/contract_state.ex +++ b/apps/explorer/lib/explorer/staking/contract_state.ex @@ -100,61 +100,71 @@ defmodule Explorer.Staking.ContractState do # dfc8bf4e = keccak256(validatorSetContract()) validator_set_contract_signature = "dfc8bf4e" - %{ - "2d21d217" => {:ok, [token_contract_address]}, - "dfc8bf4e" => {:ok, [validator_set_contract_address]} - } = - Reader.query_contract( - staking_contract_address, - staking_abi, - %{ - "#{erc_677_token_contract_signature}" => [], - "#{validator_set_contract_signature}" => [] + with %{ + "2d21d217" => {:ok, [token_contract_address]}, + "dfc8bf4e" => {:ok, [validator_set_contract_address]} + } <- + Reader.query_contract( + staking_contract_address, + staking_abi, + %{ + "#{erc_677_token_contract_signature}" => [], + "#{validator_set_contract_signature}" => [] + }, + false + ), + # 56b54bae = keccak256(blockRewardContract()) + block_reward_contract_signature = "56b54bae", + %{"56b54bae" => {:ok, [block_reward_contract_address]}} <- + Reader.query_contract( + validator_set_contract_address, + validator_set_abi, + %{ + "#{block_reward_contract_signature}" => [] + }, + false + ) do + state = %__MODULE__{ + eth_blocknumber_pull_interval: eth_blocknumber_pull_interval, + eth_subscribe_max_delay: eth_subscribe_max_delay, + snapshotting_finished: false, + timer: nil, + contracts: %{ + staking: staking_contract_address, + validator_set: validator_set_contract_address, + block_reward: block_reward_contract_address }, - false - ) - - # 56b54bae = keccak256(blockRewardContract()) - block_reward_contract_signature = "56b54bae" + abi: staking_abi ++ validator_set_abi ++ block_reward_abi + } - %{"56b54bae" => {:ok, [block_reward_contract_address]}} = - Reader.query_contract( - validator_set_contract_address, - validator_set_abi, - %{ - "#{block_reward_contract_signature}" => [] - }, - false + :ets.insert(@table_name, + block_reward_contract: %{abi: block_reward_abi, address: block_reward_contract_address}, + is_snapshotting: false, + last_change_block: 0, + pool_rewards: %{}, + seen_block: 0, + snapshotted_epoch_number: -1, + snapshotting_scheduled: false, + staking_contract: %{abi: staking_abi, address: staking_contract_address}, + token_contract: %{abi: token_abi, address: token_contract_address}, + token: get_token(token_contract_address), + validator_set_contract: %{abi: validator_set_abi, address: validator_set_contract_address} ) - state = %__MODULE__{ - eth_blocknumber_pull_interval: eth_blocknumber_pull_interval, - eth_subscribe_max_delay: eth_subscribe_max_delay, - snapshotting_finished: false, - timer: nil, - contracts: %{ - staking: staking_contract_address, - validator_set: validator_set_contract_address, - block_reward: block_reward_contract_address - }, - abi: staking_abi ++ validator_set_abi ++ block_reward_abi - } - - :ets.insert(@table_name, - block_reward_contract: %{abi: block_reward_abi, address: block_reward_contract_address}, - is_snapshotting: false, - last_change_block: 0, - pool_rewards: %{}, - seen_block: 0, - snapshotted_epoch_number: -1, - snapshotting_scheduled: false, - staking_contract: %{abi: staking_abi, address: staking_contract_address}, - token_contract: %{abi: token_abi, address: token_contract_address}, - token: get_token(token_contract_address), - validator_set_contract: %{abi: validator_set_abi, address: validator_set_contract_address} - ) - - {:ok, state, {:continue, []}} + {:ok, state, {:continue, []}} + else + _ -> + {:ok, + %__MODULE__{ + eth_blocknumber_pull_interval: eth_blocknumber_pull_interval, + eth_subscribe_max_delay: eth_subscribe_max_delay, + snapshotting_finished: false, + timer: nil, + contracts: %{ + staking: staking_contract_address + } + }, {:continue, []}} + end end def handle_continue(_, state) do @@ -564,6 +574,9 @@ defmodule Explorer.Staking.ContractState do _ -> 0 end + catch + _ -> + 0 end defp get_settings(global_responses, state, block_number) do From d4b6721e1b5ec6b64e48c0b081524fba0aea0eb4 Mon Sep 17 00:00:00 2001 From: nikitosing Date: Thu, 28 Apr 2022 17:04:39 +0300 Subject: [PATCH 074/128] Integrate ace editor to display contract sources --- .dialyzer-ignore | 4 +-- CHANGELOG.md | 1 + .../assets/css/components/_tile.scss | 9 +++++ .../assets/css/theme/_dark-theme.scss | 2 +- .../assets/js/lib/ace/src-min/ace.js | 17 ++++++++++ .../assets/js/lib/ace/src-min/mode-csharp.js | 8 +++++ .../assets/js/lib/ace/src-min/theme-chrome.js | 8 +++++ .../address_contract/code_highlighting.js | 27 ++++++++++++--- .../templates/address_contract/index.html.eex | 10 ++---- apps/block_scout_web/priv/gettext/default.pot | 34 +++++++++---------- .../priv/gettext/en/LC_MESSAGES/default.po | 34 +++++++++---------- 11 files changed, 106 insertions(+), 48 deletions(-) create mode 100644 apps/block_scout_web/assets/js/lib/ace/src-min/ace.js create mode 100644 apps/block_scout_web/assets/js/lib/ace/src-min/mode-csharp.js create mode 100644 apps/block_scout_web/assets/js/lib/ace/src-min/theme-chrome.js diff --git a/.dialyzer-ignore b/.dialyzer-ignore index ec75e5e7ddb8..d0c24c301168 100644 --- a/.dialyzer-ignore +++ b/.dialyzer-ignore @@ -23,8 +23,8 @@ lib/indexer/fetcher/token_total_supply_on_demand.ex:16 lib/explorer/exchange_rates/source.ex:110 lib/explorer/exchange_rates/source.ex:113 lib/explorer/smart_contract/solidity/verifier.ex:162 -lib/block_scout_web/templates/address_contract/index.html.eex:162 -lib/block_scout_web/templates/address_contract/index.html.eex:199 +lib/block_scout_web/templates/address_contract/index.html.eex:158 +lib/block_scout_web/templates/address_contract/index.html.eex:195 lib/explorer/staking/stake_snapshotting.ex:15: Function do_snapshotting/7 has no local return lib/explorer/staking/stake_snapshotting.ex:147 lib/explorer/third_party_integrations/sourcify.ex:70 diff --git a/CHANGELOG.md b/CHANGELOG.md index ed878652d277..c9d2fce30486 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## Current ### Features +- [#5515](https://github.com/blockscout/blockscout/pull/5515) - Integrate ace editor to display contract sources - [#5505](https://github.com/blockscout/blockscout/pull/5505) - Manage debug_traceTransaction JSON RPC method timeout - [#5491](https://github.com/blockscout/blockscout/pull/5491) - Sequential blocks broadcast on the main page - [#5312](https://github.com/blockscout/blockscout/pull/5312) - Add OpenZeppelin proxy storage slot diff --git a/apps/block_scout_web/assets/css/components/_tile.scss b/apps/block_scout_web/assets/css/components/_tile.scss index 3288d5fc3245..c1a741f460bb 100644 --- a/apps/block_scout_web/assets/css/components/_tile.scss +++ b/apps/block_scout_web/assets/css/components/_tile.scss @@ -146,6 +146,15 @@ $tile-body-a-color: #5959d8 !default; box-shadow: none; } +.tile-code { + border-radius: 4px; + border: 1px solid $border-color; + flex-grow: 1; + font-size: 12px; + line-height: 1.4rem; + padding: $tile-padding; +} + .tile-function-response { span.function-response-item { display: block; diff --git a/apps/block_scout_web/assets/css/theme/_dark-theme.scss b/apps/block_scout_web/assets/css/theme/_dark-theme.scss index ebc9ee178adf..a5365fffd933 100644 --- a/apps/block_scout_web/assets/css/theme/_dark-theme.scss +++ b/apps/block_scout_web/assets/css/theme/_dark-theme.scss @@ -161,7 +161,7 @@ $dark-stakes-banned-background: #3e314c; color: $dark-primary; } - .tile { + .tile, .tile-code { border-top-color: $dark-light; border-bottom-color: $dark-light; border-right-color: $dark-light; diff --git a/apps/block_scout_web/assets/js/lib/ace/src-min/ace.js b/apps/block_scout_web/assets/js/lib/ace/src-min/ace.js new file mode 100644 index 000000000000..223812cd9cf0 --- /dev/null +++ b/apps/block_scout_web/assets/js/lib/ace/src-min/ace.js @@ -0,0 +1,17 @@ +/* eslint-disable */(function(){function o(n){var i=e;n&&(e[n]||(e[n]={}),i=e[n]);if(!i.define||!i.define.packaged)t.original=i.define,i.define=t,i.define.packaged=!0;if(!i.require||!i.require.packaged)r.original=i.require,i.require=r,i.require.packaged=!0}var ACE_NAMESPACE="",e=function(){return this}();!e&&typeof window!="undefined"&&(e=window);if(!ACE_NAMESPACE&&typeof requirejs!="undefined")return;var t=function(e,n,r){if(typeof e!="string"){t.original?t.original.apply(this,arguments):(console.error("dropping module because define wasn't a string."),console.trace());return}arguments.length==2&&(r=n),t.modules[e]||(t.payloads[e]=r,t.modules[e]=null)};t.modules={},t.payloads={};var n=function(e,t,n){if(typeof t=="string"){var i=s(e,t);if(i!=undefined)return n&&n(),i}else if(Object.prototype.toString.call(t)==="[object Array]"){var o=[];for(var u=0,a=t.length;u=0?parseFloat((s.match(/(?:MSIE |Trident\/[0-9]+[\.0-9]+;.*rv:)([0-9]+[\.0-9]+)/)||[])[1]):parseFloat((s.match(/(?:Trident\/[0-9]+[\.0-9]+;.*rv:)([0-9]+[\.0-9]+)/)||[])[1]),t.isOldIE=t.isIE&&t.isIE<9,t.isGecko=t.isMozilla=s.match(/ Gecko\/\d+/),t.isOpera=typeof opera=="object"&&Object.prototype.toString.call(window.opera)=="[object Opera]",t.isWebKit=parseFloat(s.split("WebKit/")[1])||undefined,t.isChrome=parseFloat(s.split(" Chrome/")[1])||undefined,t.isEdge=parseFloat(s.split(" Edge/")[1])||undefined,t.isAIR=s.indexOf("AdobeAIR")>=0,t.isAndroid=s.indexOf("Android")>=0,t.isChromeOS=s.indexOf(" CrOS ")>=0,t.isIOS=/iPad|iPhone|iPod/.test(s)&&!window.MSStream,t.isIOS&&(t.isMac=!0),t.isMobile=t.isIOS||t.isAndroid}),define("ace/lib/dom",["require","exports","module","ace/lib/useragent"],function(e,t,n){"use strict";function u(){var e=o;o=null,e&&e.forEach(function(e){a(e[0],e[1])})}function a(e,n,r){if(typeof document=="undefined")return;if(o)if(r)u();else if(r===!1)return o.push([e,n]);if(s)return;var i=r;if(!r||!r.getRootNode)i=document;else{i=r.getRootNode();if(!i||i==r)i=document}var a=i.ownerDocument||i;if(n&&t.hasCssString(n,i))return null;n&&(e+="\n/*# sourceURL=ace/css/"+n+" */");var f=t.createElement("style");f.appendChild(a.createTextNode(e)),n&&(f.id=n),i==a&&(i=t.getDocumentHead(a)),i.insertBefore(f,i.firstChild)}var r=e("./useragent"),i="http://www.w3.org/1999/xhtml";t.buildDom=function l(e,t,n){if(typeof e=="string"&&e){var r=document.createTextNode(e);return t&&t.appendChild(r),r}if(!Array.isArray(e))return e&&e.appendChild&&t&&t.appendChild(e),e;if(typeof e[0]!="string"||!e[0]){var i=[];for(var s=0;s=1.5:!0,r.isChromeOS&&(t.HI_DPI=!1);if(typeof document!="undefined"){var f=document.createElement("div");t.HI_DPI&&f.style.transform!==undefined&&(t.HAS_CSS_TRANSFORMS=!0),!r.isEdge&&typeof f.style.animationName!="undefined"&&(t.HAS_CSS_ANIMATION=!0),f=null}t.HAS_CSS_TRANSFORMS?t.translate=function(e,t,n){e.style.transform="translate("+Math.round(t)+"px, "+Math.round(n)+"px)"}:t.translate=function(e,t,n){e.style.top=Math.round(n)+"px",e.style.left=Math.round(t)+"px"}}),define("ace/lib/oop",["require","exports","module"],function(e,t,n){"use strict";t.inherits=function(e,t){e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})},t.mixin=function(e,t){for(var n in t)e[n]=t[n];return e},t.implement=function(e,n){t.mixin(e,n)}}),define("ace/lib/keys",["require","exports","module","ace/lib/oop"],function(e,t,n){"use strict";var r=e("./oop"),i=function(){var e={MODIFIER_KEYS:{16:"Shift",17:"Ctrl",18:"Alt",224:"Meta",91:"MetaLeft",92:"MetaRight",93:"ContextMenu"},KEY_MODS:{ctrl:1,alt:2,option:2,shift:4,"super":8,meta:8,command:8,cmd:8,control:1},FUNCTION_KEYS:{8:"Backspace",9:"Tab",13:"Return",19:"Pause",27:"Esc",32:"Space",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"Left",38:"Up",39:"Right",40:"Down",44:"Print",45:"Insert",46:"Delete",96:"Numpad0",97:"Numpad1",98:"Numpad2",99:"Numpad3",100:"Numpad4",101:"Numpad5",102:"Numpad6",103:"Numpad7",104:"Numpad8",105:"Numpad9","-13":"NumpadEnter",112:"F1",113:"F2",114:"F3",115:"F4",116:"F5",117:"F6",118:"F7",119:"F8",120:"F9",121:"F10",122:"F11",123:"F12",144:"Numlock",145:"Scrolllock"},PRINTABLE_KEYS:{32:" ",48:"0",49:"1",50:"2",51:"3",52:"4",53:"5",54:"6",55:"7",56:"8",57:"9",59:";",61:"=",65:"a",66:"b",67:"c",68:"d",69:"e",70:"f",71:"g",72:"h",73:"i",74:"j",75:"k",76:"l",77:"m",78:"n",79:"o",80:"p",81:"q",82:"r",83:"s",84:"t",85:"u",86:"v",87:"w",88:"x",89:"y",90:"z",107:"+",109:"-",110:".",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'",111:"/",106:"*"}},t,n;for(n in e.FUNCTION_KEYS)t=e.FUNCTION_KEYS[n].toLowerCase(),e[t]=parseInt(n,10);for(n in e.PRINTABLE_KEYS)t=e.PRINTABLE_KEYS[n].toLowerCase(),e[t]=parseInt(n,10);return r.mixin(e,e.MODIFIER_KEYS),r.mixin(e,e.PRINTABLE_KEYS),r.mixin(e,e.FUNCTION_KEYS),e.enter=e["return"],e.escape=e.esc,e.del=e["delete"],e[173]="-",function(){var t=["cmd","ctrl","alt","shift"];for(var n=Math.pow(2,t.length);n--;)e.KEY_MODS[n]=t.filter(function(t){return n&e.KEY_MODS[t]}).join("-")+"-"}(),e.KEY_MODS[0]="",e.KEY_MODS[-1]="input-",e}();r.mixin(t,i),t.keyCodeToString=function(e){var t=i[e];return typeof t!="string"&&(t=String.fromCharCode(e)),t.toLowerCase()}}),define("ace/lib/event",["require","exports","module","ace/lib/keys","ace/lib/useragent"],function(e,t,n){"use strict";function a(){u=!1;try{document.createComment("").addEventListener("test",function(){},{get passive(){u={passive:!1}}})}catch(e){}}function f(){return u==undefined&&a(),u}function l(e,t,n){this.elem=e,this.type=t,this.callback=n}function d(e,t,n){var u=p(t);if(!i.isMac&&s){t.getModifierState&&(t.getModifierState("OS")||t.getModifierState("Win"))&&(u|=8);if(s.altGr){if((3&u)==3)return;s.altGr=0}if(n===18||n===17){var a="location"in t?t.location:t.keyLocation;if(n===17&&a===1)s[n]==1&&(o=t.timeStamp);else if(n===18&&u===3&&a===2){var f=t.timeStamp-o;f<50&&(s.altGr=!0)}}}n in r.MODIFIER_KEYS&&(n=-1);if(!u&&n===13){var a="location"in t?t.location:t.keyLocation;if(a===3){e(t,u,-n);if(t.defaultPrevented)return}}if(i.isChromeOS&&u&8){e(t,u,n);if(t.defaultPrevented)return;u&=-9}return!!u||n in r.FUNCTION_KEYS||n in r.PRINTABLE_KEYS?e(t,u,n):!1}function v(){s=Object.create(null)}var r=e("./keys"),i=e("./useragent"),s=null,o=0,u;l.prototype.destroy=function(){h(this.elem,this.type,this.callback),this.elem=this.type=this.callback=undefined};var c=t.addListener=function(e,t,n,r){e.addEventListener(t,n,f()),r&&r.$toDestroy.push(new l(e,t,n))},h=t.removeListener=function(e,t,n){e.removeEventListener(t,n,f())};t.stopEvent=function(e){return t.stopPropagation(e),t.preventDefault(e),!1},t.stopPropagation=function(e){e.stopPropagation&&e.stopPropagation()},t.preventDefault=function(e){e.preventDefault&&e.preventDefault()},t.getButton=function(e){return e.type=="dblclick"?0:e.type=="contextmenu"||i.isMac&&e.ctrlKey&&!e.altKey&&!e.shiftKey?2:e.button},t.capture=function(e,t,n){function i(e){t&&t(e),n&&n(e),h(r,"mousemove",t),h(r,"mouseup",i),h(r,"dragstart",i)}var r=e&&e.ownerDocument||document;return c(r,"mousemove",t),c(r,"mouseup",i),c(r,"dragstart",i),i},t.addMouseWheelListener=function(e,t,n){"onmousewheel"in e?c(e,"mousewheel",function(e){var n=8;e.wheelDeltaX!==undefined?(e.wheelX=-e.wheelDeltaX/n,e.wheelY=-e.wheelDeltaY/n):(e.wheelX=0,e.wheelY=-e.wheelDelta/n),t(e)},n):"onwheel"in e?c(e,"wheel",function(e){var n=.35;switch(e.deltaMode){case e.DOM_DELTA_PIXEL:e.wheelX=e.deltaX*n||0,e.wheelY=e.deltaY*n||0;break;case e.DOM_DELTA_LINE:case e.DOM_DELTA_PAGE:e.wheelX=(e.deltaX||0)*5,e.wheelY=(e.deltaY||0)*5}t(e)},n):c(e,"DOMMouseScroll",function(e){e.axis&&e.axis==e.HORIZONTAL_AXIS?(e.wheelX=(e.detail||0)*5,e.wheelY=0):(e.wheelX=0,e.wheelY=(e.detail||0)*5),t(e)},n)},t.addMultiMouseDownListener=function(e,n,r,s,o){function p(e){t.getButton(e)!==0?u=0:e.detail>1?(u++,u>4&&(u=1)):u=1;if(i.isIE){var o=Math.abs(e.clientX-a)>5||Math.abs(e.clientY-f)>5;if(!l||o)u=1;l&&clearTimeout(l),l=setTimeout(function(){l=null},n[u-1]||600),u==1&&(a=e.clientX,f=e.clientY)}e._clicks=u,r[s]("mousedown",e);if(u>4)u=0;else if(u>1)return r[s](h[u],e)}var u=0,a,f,l,h={2:"dblclick",3:"tripleclick",4:"quadclick"};Array.isArray(e)||(e=[e]),e.forEach(function(e){c(e,"mousedown",p,o)})};var p=function(e){return 0|(e.ctrlKey?1:0)|(e.altKey?2:0)|(e.shiftKey?4:0)|(e.metaKey?8:0)};t.getModifierString=function(e){return r.KEY_MODS[p(e)]},t.addCommandKeyListener=function(e,n,r){if(i.isOldGecko||i.isOpera&&!("KeyboardEvent"in window)){var o=null;c(e,"keydown",function(e){o=e.keyCode},r),c(e,"keypress",function(e){return d(n,e,o)},r)}else{var u=null;c(e,"keydown",function(e){s[e.keyCode]=(s[e.keyCode]||0)+1;var t=d(n,e,e.keyCode);return u=e.defaultPrevented,t},r),c(e,"keypress",function(e){u&&(e.ctrlKey||e.altKey||e.shiftKey||e.metaKey)&&(t.stopEvent(e),u=null)},r),c(e,"keyup",function(e){s[e.keyCode]=null},r),s||(v(),c(window,"focus",v))}};if(typeof window=="object"&&window.postMessage&&!i.isOldIE){var m=1;t.nextTick=function(e,n){n=n||window;var r="zero-timeout-message-"+m++,i=function(s){s.data==r&&(t.stopPropagation(s),h(n,"message",i),e())};c(n,"message",i),n.postMessage(r,"*")}}t.$idleBlocked=!1,t.onIdle=function(e,n){return setTimeout(function r(){t.$idleBlocked?setTimeout(r,100):e()},n)},t.$idleBlockId=null,t.blockIdle=function(e){t.$idleBlockId&&clearTimeout(t.$idleBlockId),t.$idleBlocked=!0,t.$idleBlockId=setTimeout(function(){t.$idleBlocked=!1},e||100)},t.nextFrame=typeof window=="object"&&(window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame||window.oRequestAnimationFrame),t.nextFrame?t.nextFrame=t.nextFrame.bind(window):t.nextFrame=function(e){setTimeout(e,17)}}),define("ace/range",["require","exports","module"],function(e,t,n){"use strict";var r=function(e,t){return e.row-t.row||e.column-t.column},i=function(e,t,n,r){this.start={row:e,column:t},this.end={row:n,column:r}};(function(){this.isEqual=function(e){return this.start.row===e.start.row&&this.end.row===e.end.row&&this.start.column===e.start.column&&this.end.column===e.end.column},this.toString=function(){return"Range: ["+this.start.row+"/"+this.start.column+"] -> ["+this.end.row+"/"+this.end.column+"]"},this.contains=function(e,t){return this.compare(e,t)==0},this.compareRange=function(e){var t,n=e.end,r=e.start;return t=this.compare(n.row,n.column),t==1?(t=this.compare(r.row,r.column),t==1?2:t==0?1:0):t==-1?-2:(t=this.compare(r.row,r.column),t==-1?-1:t==1?42:0)},this.comparePoint=function(e){return this.compare(e.row,e.column)},this.containsRange=function(e){return this.comparePoint(e.start)==0&&this.comparePoint(e.end)==0},this.intersects=function(e){var t=this.compareRange(e);return t==-1||t==0||t==1},this.isEnd=function(e,t){return this.end.row==e&&this.end.column==t},this.isStart=function(e,t){return this.start.row==e&&this.start.column==t},this.setStart=function(e,t){typeof e=="object"?(this.start.column=e.column,this.start.row=e.row):(this.start.row=e,this.start.column=t)},this.setEnd=function(e,t){typeof e=="object"?(this.end.column=e.column,this.end.row=e.row):(this.end.row=e,this.end.column=t)},this.inside=function(e,t){return this.compare(e,t)==0?this.isEnd(e,t)||this.isStart(e,t)?!1:!0:!1},this.insideStart=function(e,t){return this.compare(e,t)==0?this.isEnd(e,t)?!1:!0:!1},this.insideEnd=function(e,t){return this.compare(e,t)==0?this.isStart(e,t)?!1:!0:!1},this.compare=function(e,t){return!this.isMultiLine()&&e===this.start.row?tthis.end.column?1:0:ethis.end.row?1:this.start.row===e?t>=this.start.column?0:-1:this.end.row===e?t<=this.end.column?0:1:0},this.compareStart=function(e,t){return this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.compareEnd=function(e,t){return this.end.row==e&&this.end.column==t?1:this.compare(e,t)},this.compareInside=function(e,t){return this.end.row==e&&this.end.column==t?1:this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.clipRows=function(e,t){if(this.end.row>t)var n={row:t+1,column:0};else if(this.end.rowt)var r={row:t+1,column:0};else if(this.start.row0){t&1&&(n+=e);if(t>>=1)e+=e}return n};var r=/^\s\s*/,i=/\s\s*$/;t.stringTrimLeft=function(e){return e.replace(r,"")},t.stringTrimRight=function(e){return e.replace(i,"")},t.copyObject=function(e){var t={};for(var n in e)t[n]=e[n];return t},t.copyArray=function(e){var t=[];for(var n=0,r=e.length;nDate.now()-50?!0:r=!1},cancel:function(){r=Date.now()}}}),define("ace/keyboard/textinput",["require","exports","module","ace/lib/event","ace/lib/useragent","ace/lib/dom","ace/lib/lang","ace/clipboard","ace/lib/keys"],function(e,t,n){"use strict";var r=e("../lib/event"),i=e("../lib/useragent"),s=e("../lib/dom"),o=e("../lib/lang"),u=e("../clipboard"),a=i.isChrome<18,f=i.isIE,l=i.isChrome>63,c=400,h=e("../lib/keys"),p=h.KEY_MODS,d=i.isIOS,v=d?/\s/:/\n/,m=i.isMobile,g=function(e,t){function X(){x=!0,n.blur(),n.focus(),x=!1}function $(e){e.keyCode==27&&n.value.lengthC&&T[s]=="\n")o=h.end;else if(rC&&T.slice(0,s).split("\n").length>2)o=h.down;else if(s>C&&T[s-1]==" ")o=h.right,u=p.option;else if(s>C||s==C&&C!=N&&r==s)o=h.right;r!==s&&(u|=p.shift);if(o){var a=t.onCommandKey({},u,o);if(!a&&t.commands){o=h.keyCodeToString(o);var f=t.commands.findKeyCommand(u,o);f&&t.execCommand(f)}N=r,C=s,O("")}};document.addEventListener("selectionchange",s),t.on("destroy",function(){document.removeEventListener("selectionchange",s)})}var n=s.createElement("textarea");n.className="ace_text-input",n.setAttribute("wrap","off"),n.setAttribute("autocorrect","off"),n.setAttribute("autocapitalize","off"),n.setAttribute("spellcheck",!1),n.style.opacity="0",e.insertBefore(n,e.firstChild);var g=!1,y=!1,b=!1,w=!1,E="";m||(n.style.fontSize="1px");var S=!1,x=!1,T="",N=0,C=0,k=0;try{var L=document.activeElement===n}catch(A){}r.addListener(n,"blur",function(e){if(x)return;t.onBlur(e),L=!1},t),r.addListener(n,"focus",function(e){if(x)return;L=!0;if(i.isEdge)try{if(!document.hasFocus())return}catch(e){}t.onFocus(e),i.isEdge?setTimeout(O):O()},t),this.$focusScroll=!1,this.focus=function(){if(E||l||this.$focusScroll=="browser")return n.focus({preventScroll:!0});var e=n.style.top;n.style.position="fixed",n.style.top="0px";try{var t=n.getBoundingClientRect().top!=0}catch(r){return}var i=[];if(t){var s=n.parentElement;while(s&&s.nodeType==1)i.push(s),s.setAttribute("ace_nocontext",!0),!s.parentElement&&s.getRootNode?s=s.getRootNode().host:s=s.parentElement}n.focus({preventScroll:!0}),t&&i.forEach(function(e){e.removeAttribute("ace_nocontext")}),setTimeout(function(){n.style.position="",n.style.top=="0px"&&(n.style.top=e)},0)},this.blur=function(){n.blur()},this.isFocused=function(){return L},t.on("beforeEndOperation",function(){var e=t.curOp,r=e&&e.command&&e.command.name;if(r=="insertstring")return;var i=r&&(e.docChanged||e.selectionChanged);b&&i&&(T=n.value="",W()),O()});var O=d?function(e){if(!L||g&&!e||w)return;e||(e="");var r="\n ab"+e+"cde fg\n";r!=n.value&&(n.value=T=r);var i=4,s=4+(e.length||(t.selection.isEmpty()?0:1));(N!=i||C!=s)&&n.setSelectionRange(i,s),N=i,C=s}:function(){if(b||w)return;if(!L&&!P)return;b=!0;var e=0,r=0,i="";if(t.session){var s=t.selection,o=s.getRange(),u=s.cursor.row;e=o.start.column,r=o.end.column,i=t.session.getLine(u);if(o.start.row!=u){var a=t.session.getLine(u-1);e=o.start.rowu+1?f.length:r,r+=i.length+1,i=i+"\n"+f}else m&&u>0&&(i="\n"+i,r+=1,e+=1);i.length>c&&(e=T.length&&e.value===T&&T&&e.selectionEnd!==C},_=function(e){if(b)return;g?g=!1:M(n)?(t.selectAll(),O()):m&&n.selectionStart!=N&&O()},D=null;this.setInputHandler=function(e){D=e},this.getInputHandler=function(){return D};var P=!1,H=function(e,r){P&&(P=!1);if(y)return O(),e&&t.onPaste(e),y=!1,"";var s=n.selectionStart,o=n.selectionEnd,u=N,a=T.length-C,f=e,l=e.length-s,c=e.length-o,h=0;while(u>0&&T[h]==e[h])h++,u--;f=f.slice(h),h=1;while(a>0&&T.length-h>N-1&&T[T.length-h]==e[e.length-h])h++,a--;l-=h-1,c-=h-1;var p=f.length-h+1;p<0&&(u=-p,p=0),f=f.slice(0,p);if(!r&&!f&&!l&&!u&&!a&&!c)return"";w=!0;var d=!1;return i.isAndroid&&f==". "&&(f=" ",d=!0),f&&!u&&!a&&!l&&!c||S?t.onTextInput(f):t.onTextInput(f,{extendLeft:u,extendRight:a,restoreStart:l,restoreEnd:c}),w=!1,T=e,N=s,C=o,k=c,d?"\n":f},B=function(e){if(b)return z();if(e&&e.inputType){if(e.inputType=="historyUndo")return t.execCommand("undo");if(e.inputType=="historyRedo")return t.execCommand("redo")}var r=n.value,i=H(r,!0);(r.length>c+100||v.test(i)||m&&N<1&&N==C)&&O()},j=function(e,t,n){var r=e.clipboardData||window.clipboardData;if(!r||a)return;var i=f||n?"Text":"text/plain";try{return t?r.setData(i,t)!==!1:r.getData(i)}catch(e){if(!n)return j(e,t,!0)}},F=function(e,i){var s=t.getCopyText();if(!s)return r.preventDefault(e);j(e,s)?(d&&(O(s),g=s,setTimeout(function(){g=!1},10)),i?t.onCut():t.onCopy(),r.preventDefault(e)):(g=!0,n.value=s,n.select(),setTimeout(function(){g=!1,O(),i?t.onCut():t.onCopy()}))},I=function(e){F(e,!0)},q=function(e){F(e,!1)},R=function(e){var s=j(e);if(u.pasteCancelled())return;typeof s=="string"?(s&&t.onPaste(s,e),i.isIE&&setTimeout(O),r.preventDefault(e)):(n.value="",y=!0)};r.addCommandKeyListener(n,t.onCommandKey.bind(t),t),r.addListener(n,"select",_,t),r.addListener(n,"input",B,t),r.addListener(n,"cut",I,t),r.addListener(n,"copy",q,t),r.addListener(n,"paste",R,t),(!("oncut"in n)||!("oncopy"in n)||!("onpaste"in n))&&r.addListener(e,"keydown",function(e){if(i.isMac&&!e.metaKey||!e.ctrlKey)return;switch(e.keyCode){case 67:q(e);break;case 86:R(e);break;case 88:I(e)}},t);var U=function(e){if(b||!t.onCompositionStart||t.$readOnly)return;b={};if(S)return;e.data&&(b.useTextareaForIME=!1),setTimeout(z,0),t._signal("compositionStart"),t.on("mousedown",X);var r=t.getSelectionRange();r.end.row=r.start.row,r.end.column=r.start.column,b.markerRange=r,b.selectionStart=N,t.onCompositionStart(b),b.useTextareaForIME?(T=n.value="",N=0,C=0):(n.msGetInputContext&&(b.context=n.msGetInputContext()),n.getInputContext&&(b.context=n.getInputContext()))},z=function(){if(!b||!t.onCompositionUpdate||t.$readOnly)return;if(S)return X();if(b.useTextareaForIME)t.onCompositionUpdate(n.value);else{var e=n.value;H(e),b.markerRange&&(b.context&&(b.markerRange.start.column=b.selectionStart=b.context.compositionStartOffset),b.markerRange.end.column=b.markerRange.start.column+C-b.selectionStart+k)}},W=function(e){if(!t.onCompositionEnd||t.$readOnly)return;b=!1,t.onCompositionEnd(),t.off("mousedown",X),e&&B()},V=o.delayedCall(z,50).schedule.bind(null,null);r.addListener(n,"compositionstart",U,t),r.addListener(n,"compositionupdate",z,t),r.addListener(n,"keyup",$,t),r.addListener(n,"keydown",V,t),r.addListener(n,"compositionend",W,t),this.getElement=function(){return n},this.setCommandMode=function(e){S=e,n.readOnly=!1},this.setReadOnly=function(e){S||(n.readOnly=e)},this.setCopyWithEmptySelection=function(e){},this.onContextMenu=function(e){P=!0,O(),t._emit("nativecontextmenu",{target:t,domEvent:e}),this.moveToMouse(e,!0)},this.moveToMouse=function(e,o){E||(E=n.style.cssText),n.style.cssText=(o?"z-index:100000;":"")+(i.isIE?"opacity:0.1;":"")+"text-indent: -"+(N+C)*t.renderer.characterWidth*.5+"px;";var u=t.container.getBoundingClientRect(),a=s.computedStyle(t.container),f=u.top+(parseInt(a.borderTopWidth)||0),l=u.left+(parseInt(u.borderLeftWidth)||0),c=u.bottom-f-n.clientHeight-2,h=function(e){s.translate(n,e.clientX-l-2,Math.min(e.clientY-f-2,c))};h(e);if(e.type!="mousedown")return;t.renderer.$isMousePressed=!0,clearTimeout(J),i.isWin&&r.capture(t.container,h,K)},this.onContextMenuClose=K;var J,Q=function(e){t.textInput.onContextMenu(e),K()};r.addListener(n,"mouseup",Q,t),r.addListener(n,"mousedown",function(e){e.preventDefault(),K()},t),r.addListener(t.renderer.scroller,"contextmenu",Q,t),r.addListener(n,"contextmenu",Q,t),d&&G(e,t,n)};t.TextInput=g,t.$setUserAgentForTests=function(e,t){m=e,d=t}}),define("ace/mouse/default_handlers",["require","exports","module","ace/lib/useragent"],function(e,t,n){"use strict";function o(e){e.$clickSelection=null;var t=e.editor;t.setDefaultHandler("mousedown",this.onMouseDown.bind(e)),t.setDefaultHandler("dblclick",this.onDoubleClick.bind(e)),t.setDefaultHandler("tripleclick",this.onTripleClick.bind(e)),t.setDefaultHandler("quadclick",this.onQuadClick.bind(e)),t.setDefaultHandler("mousewheel",this.onMouseWheel.bind(e));var n=["select","startSelect","selectEnd","selectAllEnd","selectByWordsEnd","selectByLinesEnd","dragWait","dragWaitEnd","focusWait"];n.forEach(function(t){e[t]=this[t]},this),e.selectByLines=this.extendSelectionBy.bind(e,"getLineRange"),e.selectByWords=this.extendSelectionBy.bind(e,"getWordRange")}function u(e,t,n,r){return Math.sqrt(Math.pow(n-e,2)+Math.pow(r-t,2))}function a(e,t){if(e.start.row==e.end.row)var n=2*t.column-e.start.column-e.end.column;else if(e.start.row==e.end.row-1&&!e.start.column&&!e.end.column)var n=t.column-4;else var n=2*t.row-e.start.row-e.end.row;return n<0?{cursor:e.start,anchor:e.end}:{cursor:e.end,anchor:e.start}}var r=e("../lib/useragent"),i=0,s=550;(function(){this.onMouseDown=function(e){var t=e.inSelection(),n=e.getDocumentPosition();this.mousedownEvent=e;var i=this.editor,s=e.getButton();if(s!==0){var o=i.getSelectionRange(),u=o.isEmpty();(u||s==1)&&i.selection.moveToPosition(n),s==2&&(i.textInput.onContextMenu(e.domEvent),r.isMozilla||e.preventDefault());return}this.mousedownEvent.time=Date.now();if(t&&!i.isFocused()){i.focus();if(this.$focusTimeout&&!this.$clickSelection&&!i.inMultiSelectMode){this.setState("focusWait"),this.captureMouse(e);return}}return this.captureMouse(e),this.startSelect(n,e.domEvent._clicks>1),e.preventDefault()},this.startSelect=function(e,t){e=e||this.editor.renderer.screenToTextCoordinates(this.x,this.y);var n=this.editor;if(!this.mousedownEvent)return;this.mousedownEvent.getShiftKey()?n.selection.selectToPosition(e):t||n.selection.moveToPosition(e),t||this.select(),n.renderer.scroller.setCapture&&n.renderer.scroller.setCapture(),n.setStyle("ace_selecting"),this.setState("select")},this.select=function(){var e,t=this.editor,n=t.renderer.screenToTextCoordinates(this.x,this.y);if(this.$clickSelection){var r=this.$clickSelection.comparePoint(n);if(r==-1)e=this.$clickSelection.end;else if(r==1)e=this.$clickSelection.start;else{var i=a(this.$clickSelection,n);n=i.cursor,e=i.anchor}t.selection.setSelectionAnchor(e.row,e.column)}t.selection.selectToPosition(n),t.renderer.scrollCursorIntoView()},this.extendSelectionBy=function(e){var t,n=this.editor,r=n.renderer.screenToTextCoordinates(this.x,this.y),i=n.selection[e](r.row,r.column);if(this.$clickSelection){var s=this.$clickSelection.comparePoint(i.start),o=this.$clickSelection.comparePoint(i.end);if(s==-1&&o<=0){t=this.$clickSelection.end;if(i.end.row!=r.row||i.end.column!=r.column)r=i.start}else if(o==1&&s>=0){t=this.$clickSelection.start;if(i.start.row!=r.row||i.start.column!=r.column)r=i.end}else if(s==-1&&o==1)r=i.end,t=i.start;else{var u=a(this.$clickSelection,r);r=u.cursor,t=u.anchor}n.selection.setSelectionAnchor(t.row,t.column)}n.selection.selectToPosition(r),n.renderer.scrollCursorIntoView()},this.selectEnd=this.selectAllEnd=this.selectByWordsEnd=this.selectByLinesEnd=function(){this.$clickSelection=null,this.editor.unsetStyle("ace_selecting"),this.editor.renderer.scroller.releaseCapture&&this.editor.renderer.scroller.releaseCapture()},this.focusWait=function(){var e=u(this.mousedownEvent.x,this.mousedownEvent.y,this.x,this.y),t=Date.now();(e>i||t-this.mousedownEvent.time>this.$focusTimeout)&&this.startSelect(this.mousedownEvent.getDocumentPosition())},this.onDoubleClick=function(e){var t=e.getDocumentPosition(),n=this.editor,r=n.session,i=r.getBracketRange(t);i?(i.isEmpty()&&(i.start.column--,i.end.column++),this.setState("select")):(i=n.selection.getWordRange(t.row,t.column),this.setState("selectByWords")),this.$clickSelection=i,this.select()},this.onTripleClick=function(e){var t=e.getDocumentPosition(),n=this.editor;this.setState("selectByLines");var r=n.getSelectionRange();r.isMultiLine()&&r.contains(t.row,t.column)?(this.$clickSelection=n.selection.getLineRange(r.start.row),this.$clickSelection.end=n.selection.getLineRange(r.end.row).end):this.$clickSelection=n.selection.getLineRange(t.row),this.select()},this.onQuadClick=function(e){var t=this.editor;t.selectAll(),this.$clickSelection=t.getSelectionRange(),this.setState("selectAll")},this.onMouseWheel=function(e){if(e.getAccelKey())return;e.getShiftKey()&&e.wheelY&&!e.wheelX&&(e.wheelX=e.wheelY,e.wheelY=0);var t=this.editor;this.$lastScroll||(this.$lastScroll={t:0,vx:0,vy:0,allowed:0});var n=this.$lastScroll,r=e.domEvent.timeStamp,i=r-n.t,o=i?e.wheelX/i:n.vx,u=i?e.wheelY/i:n.vy;i=1&&t.renderer.isScrollableBy(e.wheelX*e.speed,0)&&(f=!0),a<=1&&t.renderer.isScrollableBy(0,e.wheelY*e.speed)&&(f=!0);if(f)n.allowed=r;else if(r-n.allowedt.session.documentToScreenRow(l.row,l.column))return c()}if(f==s)return;f=s.text.join("
"),i.setHtml(f),i.show(),t._signal("showGutterTooltip",i),t.on("mousewheel",c);if(e.$tooltipFollowsMouse)h(u);else{var p=u.domEvent.target,d=p.getBoundingClientRect(),v=i.getElement().style;v.left=d.right+"px",v.top=d.bottom+"px"}}function c(){o&&(o=clearTimeout(o)),f&&(i.hide(),f=null,t._signal("hideGutterTooltip",i),t.off("mousewheel",c))}function h(e){i.setPosition(e.x,e.y)}var t=e.editor,n=t.renderer.$gutterLayer,i=new a(t.container);e.editor.setDefaultHandler("guttermousedown",function(r){if(!t.isFocused()||r.getButton()!=0)return;var i=n.getRegion(r);if(i=="foldWidgets")return;var s=r.getDocumentPosition().row,o=t.session.selection;if(r.getShiftKey())o.selectTo(s,0);else{if(r.domEvent.detail==2)return t.selectAll(),r.preventDefault();e.$clickSelection=t.selection.getLineRange(s)}return e.setState("selectByLines"),e.captureMouse(r),r.preventDefault()});var o,u,f;e.editor.setDefaultHandler("guttermousemove",function(t){var n=t.domEvent.target||t.domEvent.srcElement;if(r.hasCssClass(n,"ace_fold-widget"))return c();f&&e.$tooltipFollowsMouse&&h(t),u=t;if(o)return;o=setTimeout(function(){o=null,u&&!e.isMousePressed?l():c()},50)}),s.addListener(t.renderer.$gutter,"mouseout",function(e){u=null;if(!f||o)return;o=setTimeout(function(){o=null,c()},50)},t),t.on("changeSession",c)}function a(e){o.call(this,e)}var r=e("../lib/dom"),i=e("../lib/oop"),s=e("../lib/event"),o=e("../tooltip").Tooltip;i.inherits(a,o),function(){this.setPosition=function(e,t){var n=window.innerWidth||document.documentElement.clientWidth,r=window.innerHeight||document.documentElement.clientHeight,i=this.getWidth(),s=this.getHeight();e+=15,t+=15,e+i>n&&(e-=e+i-n),t+s>r&&(t-=20+s),o.prototype.setPosition.call(this,e,t)}}.call(a.prototype),t.GutterHandler=u}),define("ace/mouse/mouse_event",["require","exports","module","ace/lib/event","ace/lib/useragent"],function(e,t,n){"use strict";var r=e("../lib/event"),i=e("../lib/useragent"),s=t.MouseEvent=function(e,t){this.domEvent=e,this.editor=t,this.x=this.clientX=e.clientX,this.y=this.clientY=e.clientY,this.$pos=null,this.$inSelection=null,this.propagationStopped=!1,this.defaultPrevented=!1};(function(){this.stopPropagation=function(){r.stopPropagation(this.domEvent),this.propagationStopped=!0},this.preventDefault=function(){r.preventDefault(this.domEvent),this.defaultPrevented=!0},this.stop=function(){this.stopPropagation(),this.preventDefault()},this.getDocumentPosition=function(){return this.$pos?this.$pos:(this.$pos=this.editor.renderer.screenToTextCoordinates(this.clientX,this.clientY),this.$pos)},this.inSelection=function(){if(this.$inSelection!==null)return this.$inSelection;var e=this.editor,t=e.getSelectionRange();if(t.isEmpty())this.$inSelection=!1;else{var n=this.getDocumentPosition();this.$inSelection=t.contains(n.row,n.column)}return this.$inSelection},this.getButton=function(){return r.getButton(this.domEvent)},this.getShiftKey=function(){return this.domEvent.shiftKey},this.getAccelKey=i.isMac?function(){return this.domEvent.metaKey}:function(){return this.domEvent.ctrlKey}}).call(s.prototype)}),define("ace/mouse/dragdrop_handler",["require","exports","module","ace/lib/dom","ace/lib/event","ace/lib/useragent"],function(e,t,n){"use strict";function f(e){function T(e,n){var r=Date.now(),i=!n||e.row!=n.row,s=!n||e.column!=n.column;if(!S||i||s)t.moveCursorToPosition(e),S=r,x={x:p,y:d};else{var o=l(x.x,x.y,p,d);o>a?S=null:r-S>=u&&(t.renderer.scrollCursorIntoView(),S=null)}}function N(e,n){var r=Date.now(),i=t.renderer.layerConfig.lineHeight,s=t.renderer.layerConfig.characterWidth,u=t.renderer.scroller.getBoundingClientRect(),a={x:{left:p-u.left,right:u.right-p},y:{top:d-u.top,bottom:u.bottom-d}},f=Math.min(a.x.left,a.x.right),l=Math.min(a.y.top,a.y.bottom),c={row:e.row,column:e.column};f/s<=2&&(c.column+=a.x.left=o&&t.renderer.scrollCursorIntoView(c):E=r:E=null}function C(){var e=g;g=t.renderer.screenToTextCoordinates(p,d),T(g,e),N(g,e)}function k(){m=t.selection.toOrientedRange(),h=t.session.addMarker(m,"ace_selection",t.getSelectionStyle()),t.clearSelection(),t.isFocused()&&t.renderer.$cursorLayer.setBlinking(!1),clearInterval(v),C(),v=setInterval(C,20),y=0,i.addListener(document,"mousemove",O)}function L(){clearInterval(v),t.session.removeMarker(h),h=null,t.selection.fromOrientedRange(m),t.isFocused()&&!w&&t.$resetCursorStyle(),m=null,g=null,y=0,E=null,S=null,i.removeListener(document,"mousemove",O)}function O(){A==null&&(A=setTimeout(function(){A!=null&&h&&L()},20))}function M(e){var t=e.types;return!t||Array.prototype.some.call(t,function(e){return e=="text/plain"||e=="Text"})}function _(e){var t=["copy","copymove","all","uninitialized"],n=["move","copymove","linkmove","all","uninitialized"],r=s.isMac?e.altKey:e.ctrlKey,i="uninitialized";try{i=e.dataTransfer.effectAllowed.toLowerCase()}catch(e){}var o="none";return r&&t.indexOf(i)>=0?o="copy":n.indexOf(i)>=0?o="move":t.indexOf(i)>=0&&(o="copy"),o}var t=e.editor,n=r.createElement("div");n.style.cssText="top:-100px;position:absolute;z-index:2147483647;opacity:0.5",n.textContent="\u00a0";var f=["dragWait","dragWaitEnd","startDrag","dragReadyEnd","onMouseDrag"];f.forEach(function(t){e[t]=this[t]},this),t.on("mousedown",this.onMouseDown.bind(e));var c=t.container,h,p,d,v,m,g,y=0,b,w,E,S,x;this.onDragStart=function(e){if(this.cancelDrag||!c.draggable){var r=this;return setTimeout(function(){r.startSelect(),r.captureMouse(e)},0),e.preventDefault()}m=t.getSelectionRange();var i=e.dataTransfer;i.effectAllowed=t.getReadOnly()?"copy":"copyMove",t.container.appendChild(n),i.setDragImage&&i.setDragImage(n,0,0),setTimeout(function(){t.container.removeChild(n)}),i.clearData(),i.setData("Text",t.session.getTextRange()),w=!0,this.setState("drag")},this.onDragEnd=function(e){c.draggable=!1,w=!1,this.setState(null);if(!t.getReadOnly()){var n=e.dataTransfer.dropEffect;!b&&n=="move"&&t.session.remove(t.getSelectionRange()),t.$resetCursorStyle()}this.editor.unsetStyle("ace_dragging"),this.editor.renderer.setCursorStyle("")},this.onDragEnter=function(e){if(t.getReadOnly()||!M(e.dataTransfer))return;return p=e.clientX,d=e.clientY,h||k(),y++,e.dataTransfer.dropEffect=b=_(e),i.preventDefault(e)},this.onDragOver=function(e){if(t.getReadOnly()||!M(e.dataTransfer))return;return p=e.clientX,d=e.clientY,h||(k(),y++),A!==null&&(A=null),e.dataTransfer.dropEffect=b=_(e),i.preventDefault(e)},this.onDragLeave=function(e){y--;if(y<=0&&h)return L(),b=null,i.preventDefault(e)},this.onDrop=function(e){if(!g)return;var n=e.dataTransfer;if(w)switch(b){case"move":m.contains(g.row,g.column)?m={start:g,end:g}:m=t.moveText(m,g);break;case"copy":m=t.moveText(m,g,!0)}else{var r=n.getData("Text");m={start:g,end:t.session.insert(g,r)},t.focus(),b=null}return L(),i.preventDefault(e)},i.addListener(c,"dragstart",this.onDragStart.bind(e),t),i.addListener(c,"dragend",this.onDragEnd.bind(e),t),i.addListener(c,"dragenter",this.onDragEnter.bind(e),t),i.addListener(c,"dragover",this.onDragOver.bind(e),t),i.addListener(c,"dragleave",this.onDragLeave.bind(e),t),i.addListener(c,"drop",this.onDrop.bind(e),t);var A=null}function l(e,t,n,r){return Math.sqrt(Math.pow(n-e,2)+Math.pow(r-t,2))}var r=e("../lib/dom"),i=e("../lib/event"),s=e("../lib/useragent"),o=200,u=200,a=5;(function(){this.dragWait=function(){var e=Date.now()-this.mousedownEvent.time;e>this.editor.getDragDelay()&&this.startDrag()},this.dragWaitEnd=function(){var e=this.editor.container;e.draggable=!1,this.startSelect(this.mousedownEvent.getDocumentPosition()),this.selectEnd()},this.dragReadyEnd=function(e){this.editor.$resetCursorStyle(),this.editor.unsetStyle("ace_dragging"),this.editor.renderer.setCursorStyle(""),this.dragWaitEnd()},this.startDrag=function(){this.cancelDrag=!1;var e=this.editor,t=e.container;t.draggable=!0,e.renderer.$cursorLayer.setBlinking(!1),e.setStyle("ace_dragging");var n=s.isWin?"default":"move";e.renderer.setCursorStyle(n),this.setState("dragReady")},this.onMouseDrag=function(e){var t=this.editor.container;if(s.isIE&&this.state=="dragReady"){var n=l(this.mousedownEvent.x,this.mousedownEvent.y,this.x,this.y);n>3&&t.dragDrop()}if(this.state==="dragWait"){var n=l(this.mousedownEvent.x,this.mousedownEvent.y,this.x,this.y);n>0&&(t.draggable=!1,this.startSelect(this.mousedownEvent.getDocumentPosition()))}},this.onMouseDown=function(e){if(!this.$dragEnabled)return;this.mousedownEvent=e;var t=this.editor,n=e.inSelection(),r=e.getButton(),i=e.domEvent.detail||1;if(i===1&&r===0&&n){if(e.editor.inMultiSelectMode&&(e.getAccelKey()||e.getShiftKey()))return;this.mousedownEvent.time=Date.now();var o=e.domEvent.target||e.domEvent.srcElement;"unselectable"in o&&(o.unselectable="on");if(t.getDragDelay()){if(s.isWebKit){this.cancelDrag=!0;var u=t.container;u.draggable=!0}this.setState("dragWait")}else this.startDrag();this.captureMouse(e,this.onMouseDrag.bind(this)),e.defaultPrevented=!0}}}).call(f.prototype),t.DragdropHandler=f}),define("ace/mouse/touch_handler",["require","exports","module","ace/mouse/mouse_event","ace/lib/event","ace/lib/dom"],function(e,t,n){"use strict";var r=e("./mouse_event").MouseEvent,i=e("../lib/event"),s=e("../lib/dom");t.addTouchListeners=function(e,t){function b(){var e=window.navigator&&window.navigator.clipboard,r=!1,i=function(){var n=t.getCopyText(),i=t.session.getUndoManager().hasUndo();y.replaceChild(s.buildDom(r?["span",!n&&["span",{"class":"ace_mobile-button",action:"selectall"},"Select All"],n&&["span",{"class":"ace_mobile-button",action:"copy"},"Copy"],n&&["span",{"class":"ace_mobile-button",action:"cut"},"Cut"],e&&["span",{"class":"ace_mobile-button",action:"paste"},"Paste"],i&&["span",{"class":"ace_mobile-button",action:"undo"},"Undo"],["span",{"class":"ace_mobile-button",action:"find"},"Find"],["span",{"class":"ace_mobile-button",action:"openCommandPallete"},"Pallete"]]:["span"]),y.firstChild)},o=function(n){var s=n.target.getAttribute("action");if(s=="more"||!r)return r=!r,i();if(s=="paste")e.readText().then(function(e){t.execCommand(s,e)});else if(s){if(s=="cut"||s=="copy")e?e.writeText(t.getCopyText()):document.execCommand("copy");t.execCommand(s)}y.firstChild.style.display="none",r=!1,s!="openCommandPallete"&&t.focus()};y=s.buildDom(["div",{"class":"ace_mobile-menu",ontouchstart:function(e){n="menu",e.stopPropagation(),e.preventDefault(),t.textInput.focus()},ontouchend:function(e){e.stopPropagation(),e.preventDefault(),o(e)},onclick:o},["span"],["span",{"class":"ace_mobile-button",action:"more"},"..."]],t.container)}function w(){y||b();var e=t.selection.cursor,n=t.renderer.textToScreenCoordinates(e.row,e.column),r=t.renderer.textToScreenCoordinates(0,0).pageX,i=t.renderer.scrollLeft,s=t.container.getBoundingClientRect();y.style.top=n.pageY-s.top-3+"px",n.pageX-s.left=2?t.selection.getLineRange(p.row):t.session.getBracketRange(p);e&&!e.isEmpty()?t.selection.setRange(e):t.selection.selectWord(),n="wait"}function T(){h+=60,c=setInterval(function(){h--<=0&&(clearInterval(c),c=null),Math.abs(v)<.01&&(v=0),Math.abs(m)<.01&&(m=0),h<20&&(v=.9*v),h<20&&(m=.9*m);var e=t.session.getScrollTop();t.renderer.scrollBy(10*v,10*m),e==t.session.getScrollTop()&&(h=0)},10)}var n="scroll",o,u,a,f,l,c,h=0,p,d=0,v=0,m=0,g,y;i.addListener(e,"contextmenu",function(e){if(!g)return;var n=t.textInput.getElement();n.focus()},t),i.addListener(e,"touchstart",function(e){var i=e.touches;if(l||i.length>1){clearTimeout(l),l=null,a=-1,n="zoom";return}g=t.$mouseHandler.isMousePressed=!0;var s=t.renderer.layerConfig.lineHeight,c=t.renderer.layerConfig.lineHeight,y=e.timeStamp;f=y;var b=i[0],w=b.clientX,E=b.clientY;Math.abs(o-w)+Math.abs(u-E)>s&&(a=-1),o=e.clientX=w,u=e.clientY=E,v=m=0;var T=new r(e,t);p=T.getDocumentPosition();if(y-a<500&&i.length==1&&!h)d++,e.preventDefault(),e.button=0,x();else{d=0;var N=t.selection.cursor,C=t.selection.isEmpty()?N:t.selection.anchor,k=t.renderer.$cursorLayer.getPixelPosition(N,!0),L=t.renderer.$cursorLayer.getPixelPosition(C,!0),A=t.renderer.scroller.getBoundingClientRect(),O=t.renderer.layerConfig.offset,M=t.renderer.scrollLeft,_=function(e,t){return e/=c,t=t/s-.75,e*e+t*t};if(e.clientXP?"cursor":"anchor"),P<3.5?n="anchor":D<3.5?n="cursor":n="scroll",l=setTimeout(S,450)}a=y},t),i.addListener(e,"touchend",function(e){g=t.$mouseHandler.isMousePressed=!1,c&&clearInterval(c),n=="zoom"?(n="",h=0):l?(t.selection.moveToPosition(p),h=0,w()):n=="scroll"?(T(),E()):w(),clearTimeout(l),l=null},t),i.addListener(e,"touchmove",function(e){l&&(clearTimeout(l),l=null);var i=e.touches;if(i.length>1||n=="zoom")return;var s=i[0],a=o-s.clientX,c=u-s.clientY;if(n=="wait"){if(!(a*a+c*c>4))return e.preventDefault();n="cursor"}o=s.clientX,u=s.clientY,e.clientX=s.clientX,e.clientY=s.clientY;var h=e.timeStamp,p=h-f;f=h;if(n=="scroll"){var d=new r(e,t);d.speed=1,d.wheelX=a,d.wheelY=c,10*Math.abs(a)1&&(i=n[n.length-2]);var o=f[t+"Path"];return o==null?o=f.basePath:r=="/"&&(t=r=""),o&&o.slice(-1)!="/"&&(o+="/"),o+t+r+i+this.get("suffix")},t.setModuleUrl=function(e,t){return f.$moduleUrls[e]=t},t.$loading={},t.loadModule=function(n,r){var i,o;Array.isArray(n)&&(o=n[0],n=n[1]);try{i=e(n)}catch(u){}if(i&&!t.$loading[n])return r&&r(i);t.$loading[n]||(t.$loading[n]=[]),t.$loading[n].push(r);if(t.$loading[n].length>1)return;var a=function(){e([n],function(e){t._emit("load.module",{name:n,module:e});var r=t.$loading[n];t.$loading[n]=null,r.forEach(function(t){t&&t(e)})})};if(!t.get("packaged"))return a();s.loadScript(t.moduleUrl(n,o),a),l()};var l=function(){!f.basePath&&!f.workerPath&&!f.modePath&&!f.themePath&&!Object.keys(f.$moduleUrls).length&&(console.error("Unable to infer path to ace from script src,","use ace.config.set('basePath', 'path') to enable dynamic loading of modes and themes","or with webpack use ace/webpack-resolver"),l=function(){})};t.init=c,t.version="1.4.14"}),define("ace/mouse/mouse_handler",["require","exports","module","ace/lib/event","ace/lib/useragent","ace/mouse/default_handlers","ace/mouse/default_gutter_handler","ace/mouse/mouse_event","ace/mouse/dragdrop_handler","ace/mouse/touch_handler","ace/config"],function(e,t,n){"use strict";var r=e("../lib/event"),i=e("../lib/useragent"),s=e("./default_handlers").DefaultHandlers,o=e("./default_gutter_handler").GutterHandler,u=e("./mouse_event").MouseEvent,a=e("./dragdrop_handler").DragdropHandler,f=e("./touch_handler").addTouchListeners,l=e("../config"),c=function(e){var t=this;this.editor=e,new s(this),new o(this),new a(this);var n=function(t){var n=!document.hasFocus||!document.hasFocus()||!e.isFocused()&&document.activeElement==(e.textInput&&e.textInput.getElement());n&&window.focus(),e.focus()},u=e.renderer.getMouseEventTarget();r.addListener(u,"click",this.onMouseEvent.bind(this,"click"),e),r.addListener(u,"mousemove",this.onMouseMove.bind(this,"mousemove"),e),r.addMultiMouseDownListener([u,e.renderer.scrollBarV&&e.renderer.scrollBarV.inner,e.renderer.scrollBarH&&e.renderer.scrollBarH.inner,e.textInput&&e.textInput.getElement()].filter(Boolean),[400,300,250],this,"onMouseEvent",e),r.addMouseWheelListener(e.container,this.onMouseWheel.bind(this,"mousewheel"),e),f(e.container,e);var l=e.renderer.$gutter;r.addListener(l,"mousedown",this.onMouseEvent.bind(this,"guttermousedown"),e),r.addListener(l,"click",this.onMouseEvent.bind(this,"gutterclick"),e),r.addListener(l,"dblclick",this.onMouseEvent.bind(this,"gutterdblclick"),e),r.addListener(l,"mousemove",this.onMouseEvent.bind(this,"guttermousemove"),e),r.addListener(u,"mousedown",n,e),r.addListener(l,"mousedown",n,e),i.isIE&&e.renderer.scrollBarV&&(r.addListener(e.renderer.scrollBarV.element,"mousedown",n,e),r.addListener(e.renderer.scrollBarH.element,"mousedown",n,e)),e.on("mousemove",function(n){if(t.state||t.$dragDelay||!t.$dragEnabled)return;var r=e.renderer.screenToTextCoordinates(n.x,n.y),i=e.session.selection.getRange(),s=e.renderer;!i.isEmpty()&&i.insideStart(r.row,r.column)?s.setCursorStyle("default"):s.setCursorStyle("")},e)};(function(){this.onMouseEvent=function(e,t){if(!this.editor.session)return;this.editor._emit(e,new u(t,this.editor))},this.onMouseMove=function(e,t){var n=this.editor._eventRegistry&&this.editor._eventRegistry.mousemove;if(!n||!n.length)return;this.editor._emit(e,new u(t,this.editor))},this.onMouseWheel=function(e,t){var n=new u(t,this.editor);n.speed=this.$scrollSpeed*2,n.wheelX=t.wheelX,n.wheelY=t.wheelY,this.editor._emit(e,n)},this.setState=function(e){this.state=e},this.captureMouse=function(e,t){this.x=e.x,this.y=e.y,this.isMousePressed=!0;var n=this.editor,s=this.editor.renderer;s.$isMousePressed=!0;var o=this,a=function(e){if(!e)return;if(i.isWebKit&&!e.which&&o.releaseMouse)return o.releaseMouse();o.x=e.clientX,o.y=e.clientY,t&&t(e),o.mouseEvent=new u(e,o.editor),o.$mouseMoved=!0},f=function(e){n.off("beforeEndOperation",c),clearInterval(h),n.session&&l(),o[o.state+"End"]&&o[o.state+"End"](e),o.state="",o.isMousePressed=s.$isMousePressed=!1,s.$keepTextAreaAtCursor&&s.$moveTextAreaToCursor(),o.$onCaptureMouseMove=o.releaseMouse=null,e&&o.onMouseEvent("mouseup",e),n.endOperation()},l=function(){o[o.state]&&o[o.state](),o.$mouseMoved=!1};if(i.isOldIE&&e.domEvent.type=="dblclick")return setTimeout(function(){f(e)});var c=function(e){if(!o.releaseMouse)return;n.curOp.command.name&&n.curOp.selectionChanged&&(o[o.state+"End"]&&o[o.state+"End"](),o.state="",o.releaseMouse())};n.on("beforeEndOperation",c),n.startOperation({command:{name:"mouse"}}),o.$onCaptureMouseMove=a,o.releaseMouse=r.capture(this.editor.container,a,f);var h=setInterval(l,20)},this.releaseMouse=null,this.cancelContextMenu=function(){var e=function(t){if(t&&t.domEvent&&t.domEvent.type!="contextmenu")return;this.editor.off("nativecontextmenu",e),t&&t.domEvent&&r.stopEvent(t.domEvent)}.bind(this);setTimeout(e,10),this.editor.on("nativecontextmenu",e)},this.destroy=function(){this.releaseMouse&&this.releaseMouse()}}).call(c.prototype),l.defineOptions(c.prototype,"mouseHandler",{scrollSpeed:{initialValue:2},dragDelay:{initialValue:i.isMac?150:0},dragEnabled:{initialValue:!0},focusTimeout:{initialValue:0},tooltipFollowsMouse:{initialValue:!0}}),t.MouseHandler=c}),define("ace/mouse/fold_handler",["require","exports","module","ace/lib/dom"],function(e,t,n){"use strict";function i(e){e.on("click",function(t){var n=t.getDocumentPosition(),i=e.session,s=i.getFoldAt(n.row,n.column,1);s&&(t.getAccelKey()?i.removeFold(s):i.expandFold(s),t.stop());var o=t.domEvent&&t.domEvent.target;o&&r.hasCssClass(o,"ace_inline_button")&&r.hasCssClass(o,"ace_toggle_wrap")&&(i.setOption("wrap",!i.getUseWrapMode()),e.renderer.scrollCursorIntoView())}),e.on("gutterclick",function(t){var n=e.renderer.$gutterLayer.getRegion(t);if(n=="foldWidgets"){var r=t.getDocumentPosition().row,i=e.session;i.foldWidgets&&i.foldWidgets[r]&&e.session.onFoldWidgetClick(r,t),e.isFocused()||e.focus(),t.stop()}}),e.on("gutterdblclick",function(t){var n=e.renderer.$gutterLayer.getRegion(t);if(n=="foldWidgets"){var r=t.getDocumentPosition().row,i=e.session,s=i.getParentFoldRangeData(r,!0),o=s.range||s.firstRange;if(o){r=o.start.row;var u=i.getFoldAt(r,i.getLine(r).length,1);u?i.removeFold(u):(i.addFold("...",o),e.renderer.scrollCursorIntoView({row:o.start.row,column:0}))}t.stop()}})}var r=e("../lib/dom");t.FoldHandler=i}),define("ace/keyboard/keybinding",["require","exports","module","ace/lib/keys","ace/lib/event"],function(e,t,n){"use strict";var r=e("../lib/keys"),i=e("../lib/event"),s=function(e){this.$editor=e,this.$data={editor:e},this.$handlers=[],this.setDefaultHandler(e.commands)};(function(){this.setDefaultHandler=function(e){this.removeKeyboardHandler(this.$defaultHandler),this.$defaultHandler=e,this.addKeyboardHandler(e,0)},this.setKeyboardHandler=function(e){var t=this.$handlers;if(t[t.length-1]==e)return;while(t[t.length-1]&&t[t.length-1]!=this.$defaultHandler)this.removeKeyboardHandler(t[t.length-1]);this.addKeyboardHandler(e,1)},this.addKeyboardHandler=function(e,t){if(!e)return;typeof e=="function"&&!e.handleKeyboard&&(e.handleKeyboard=e);var n=this.$handlers.indexOf(e);n!=-1&&this.$handlers.splice(n,1),t==undefined?this.$handlers.push(e):this.$handlers.splice(t,0,e),n==-1&&e.attach&&e.attach(this.$editor)},this.removeKeyboardHandler=function(e){var t=this.$handlers.indexOf(e);return t==-1?!1:(this.$handlers.splice(t,1),e.detach&&e.detach(this.$editor),!0)},this.getKeyboardHandler=function(){return this.$handlers[this.$handlers.length-1]},this.getStatusText=function(){var e=this.$data,t=e.editor;return this.$handlers.map(function(n){return n.getStatusText&&n.getStatusText(t,e)||""}).filter(Boolean).join(" ")},this.$callKeyboardHandlers=function(e,t,n,r){var s,o=!1,u=this.$editor.commands;for(var a=this.$handlers.length;a--;){s=this.$handlers[a].handleKeyboard(this.$data,e,t,n,r);if(!s||!s.command)continue;s.command=="null"?o=!0:o=u.exec(s.command,this.$editor,s.args,r),o&&r&&e!=-1&&s.passEvent!=1&&s.command.passEvent!=1&&i.stopEvent(r);if(o)break}return!o&&e==-1&&(s={command:"insertstring"},o=u.exec("insertstring",this.$editor,t)),o&&this.$editor._signal&&this.$editor._signal("keyboardActivity",s),o},this.onCommandKey=function(e,t,n){var i=r.keyCodeToString(n);return this.$callKeyboardHandlers(t,i,n,e)},this.onTextInput=function(e){return this.$callKeyboardHandlers(-1,e)}}).call(s.prototype),t.KeyBinding=s}),define("ace/lib/bidiutil",["require","exports","module"],function(e,t,n){"use strict";function F(e,t,n,r){var i=s?d:p,c=null,h=null,v=null,m=0,g=null,y=null,b=-1,w=null,E=null,T=[];if(!r)for(w=0,r=[];w0)if(g==16){for(w=b;w-1){for(w=b;w=0;C--){if(r[C]!=N)break;t[C]=s}}}function I(e,t,n){if(o=e){u=i+1;while(u=e)u++;for(a=i,l=u-1;a=t.length||(o=n[r-1])!=b&&o!=w||(c=t[r+1])!=b&&c!=w)return E;return u&&(c=w),c==o?c:E;case k:o=r>0?n[r-1]:S;if(o==b&&r+10&&n[r-1]==b)return b;if(u)return E;p=r+1,h=t.length;while(p=1425&&d<=2303||d==64286;o=t[p];if(v&&(o==y||o==T))return y}if(r<1||(o=t[r-1])==S)return E;return n[r-1];case S:return u=!1,f=!0,s;case x:return l=!0,E;case O:case M:case D:case P:case _:u=!1;case H:return E}}function R(e){var t=e.charCodeAt(0),n=t>>8;return n==0?t>191?g:B[t]:n==5?/[\u0591-\u05f4]/.test(e)?y:g:n==6?/[\u0610-\u061a\u064b-\u065f\u06d6-\u06e4\u06e7-\u06ed]/.test(e)?A:/[\u0660-\u0669\u066b-\u066c]/.test(e)?w:t==1642?L:/[\u06f0-\u06f9]/.test(e)?b:T:n==32&&t<=8287?j[t&255]:n==254?t>=65136?T:E:E}function U(e){return e>="\u064b"&&e<="\u0655"}var r=["\u0621","\u0641"],i=["\u063a","\u064a"],s=0,o=0,u=!1,a=!1,f=!1,l=!1,c=!1,h=!1,p=[[0,3,0,1,0,0,0],[0,3,0,1,2,2,0],[0,3,0,17,2,0,1],[0,3,5,5,4,1,0],[0,3,21,21,4,0,1],[0,3,5,5,4,2,0]],d=[[2,0,1,1,0,1,0],[2,0,1,1,0,2,0],[2,0,2,1,3,2,0],[2,0,2,33,3,1,1]],v=0,m=1,g=0,y=1,b=2,w=3,E=4,S=5,x=6,T=7,N=8,C=9,k=10,L=11,A=12,O=13,M=14,_=15,D=16,P=17,H=18,B=[H,H,H,H,H,H,H,H,H,x,S,x,N,S,H,H,H,H,H,H,H,H,H,H,H,H,H,H,S,S,S,x,N,E,E,L,L,L,E,E,E,E,E,k,C,k,C,C,b,b,b,b,b,b,b,b,b,b,C,E,E,E,E,E,E,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,E,E,E,E,E,E,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,E,E,E,E,H,H,H,H,H,H,S,H,H,H,H,H,H,H,H,H,H,H,H,H,H,H,H,H,H,H,H,H,H,H,H,H,H,C,E,L,L,L,L,E,E,E,E,g,E,E,H,E,E,L,L,b,b,E,g,E,E,E,b,g,E,E,E,E,E],j=[N,N,N,N,N,N,N,N,N,N,N,H,H,H,g,y,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,N,S,O,M,_,D,P,C,L,L,L,L,L,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,C,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,N];t.L=g,t.R=y,t.EN=b,t.ON_R=3,t.AN=4,t.R_H=5,t.B=6,t.RLE=7,t.DOT="\u00b7",t.doBidiReorder=function(e,n,r){if(e.length<2)return{};var i=e.split(""),o=new Array(i.length),u=new Array(i.length),a=[];s=r?m:v,F(i,a,i.length,n);for(var f=0;fT&&n[f]0&&i[f-1]==="\u0644"&&/\u0622|\u0623|\u0625|\u0627/.test(i[f])&&(a[f-1]=a[f]=t.R_H,f++);i[i.length-1]===t.DOT&&(a[i.length-1]=t.B),i[0]==="\u202b"&&(a[0]=t.RLE);for(var f=0;f=0&&(e=this.session.$docRowCache[n])}return e},this.getSplitIndex=function(){var e=0,t=this.session.$screenRowCache;if(t.length){var n,r=this.session.$getRowCacheIndex(t,this.currentRow);while(this.currentRow-e>0){n=this.session.$getRowCacheIndex(t,this.currentRow-e-1);if(n!==r)break;r=n,e++}}else e=this.currentRow;return e},this.updateRowLine=function(e,t){e===undefined&&(e=this.getDocumentRow());var n=e===this.session.getLength()-1,s=n?this.EOF:this.EOL;this.wrapIndent=0,this.line=this.session.getLine(e),this.isRtlDir=this.$isRtl||this.line.charAt(0)===this.RLE;if(this.session.$useWrapMode){var o=this.session.$wrapData[e];o&&(t===undefined&&(t=this.getSplitIndex()),t>0&&o.length?(this.wrapIndent=o.indent,this.wrapOffset=this.wrapIndent*this.charWidths[r.L],this.line=tt?this.session.getOverwrite()?e:e-1:t,i=r.getVisualFromLogicalIdx(n,this.bidiMap),s=this.bidiMap.bidiLevels,o=0;!this.session.getOverwrite()&&e<=t&&s[i]%2!==0&&i++;for(var u=0;ut&&s[i]%2===0&&(o+=this.charWidths[s[i]]),this.wrapIndent&&(o+=this.isRtlDir?-1*this.wrapOffset:this.wrapOffset),this.isRtlDir&&(o+=this.rtlLineOffset),o},this.getSelections=function(e,t){var n=this.bidiMap,r=n.bidiLevels,i,s=[],o=0,u=Math.min(e,t)-this.wrapIndent,a=Math.max(e,t)-this.wrapIndent,f=!1,l=!1,c=0;this.wrapIndent&&(o+=this.isRtlDir?-1*this.wrapOffset:this.wrapOffset);for(var h,p=0;p=u&&hn+s/2){n+=s;if(r===i.length-1){s=0;break}s=this.charWidths[i[++r]]}return r>0&&i[r-1]%2!==0&&i[r]%2===0?(e0&&i[r-1]%2===0&&i[r]%2!==0?t=1+(e>n?this.bidiMap.logicalFromVisual[r]:this.bidiMap.logicalFromVisual[r-1]):this.isRtlDir&&r===i.length-1&&s===0&&i[r-1]%2===0||!this.isRtlDir&&r===0&&i[r]%2!==0?t=1+this.bidiMap.logicalFromVisual[r]:(r>0&&i[r-1]%2!==0&&s!==0&&r--,t=this.bidiMap.logicalFromVisual[r]),t===0&&this.isRtlDir&&t++,t+this.wrapIndent}}).call(o.prototype),t.BidiHandler=o}),define("ace/selection",["require","exports","module","ace/lib/oop","ace/lib/lang","ace/lib/event_emitter","ace/range"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/lang"),s=e("./lib/event_emitter").EventEmitter,o=e("./range").Range,u=function(e){this.session=e,this.doc=e.getDocument(),this.clearSelection(),this.cursor=this.lead=this.doc.createAnchor(0,0),this.anchor=this.doc.createAnchor(0,0),this.$silent=!1;var t=this;this.cursor.on("change",function(e){t.$cursorChanged=!0,t.$silent||t._emit("changeCursor"),!t.$isEmpty&&!t.$silent&&t._emit("changeSelection"),!t.$keepDesiredColumnOnChange&&e.old.column!=e.value.column&&(t.$desiredColumn=null)}),this.anchor.on("change",function(){t.$anchorChanged=!0,!t.$isEmpty&&!t.$silent&&t._emit("changeSelection")})};(function(){r.implement(this,s),this.isEmpty=function(){return this.$isEmpty||this.anchor.row==this.lead.row&&this.anchor.column==this.lead.column},this.isMultiLine=function(){return!this.$isEmpty&&this.anchor.row!=this.cursor.row},this.getCursor=function(){return this.lead.getPosition()},this.setSelectionAnchor=function(e,t){this.$isEmpty=!1,this.anchor.setPosition(e,t)},this.getAnchor=this.getSelectionAnchor=function(){return this.$isEmpty?this.getSelectionLead():this.anchor.getPosition()},this.getSelectionLead=function(){return this.lead.getPosition()},this.isBackwards=function(){var e=this.anchor,t=this.lead;return e.row>t.row||e.row==t.row&&e.column>t.column},this.getRange=function(){var e=this.anchor,t=this.lead;return this.$isEmpty?o.fromPoints(t,t):this.isBackwards()?o.fromPoints(t,e):o.fromPoints(e,t)},this.clearSelection=function(){this.$isEmpty||(this.$isEmpty=!0,this._emit("changeSelection"))},this.selectAll=function(){this.$setSelection(0,0,Number.MAX_VALUE,Number.MAX_VALUE)},this.setRange=this.setSelectionRange=function(e,t){var n=t?e.end:e.start,r=t?e.start:e.end;this.$setSelection(n.row,n.column,r.row,r.column)},this.$setSelection=function(e,t,n,r){if(this.$silent)return;var i=this.$isEmpty,s=this.inMultiSelectMode;this.$silent=!0,this.$cursorChanged=this.$anchorChanged=!1,this.anchor.setPosition(e,t),this.cursor.setPosition(n,r),this.$isEmpty=!o.comparePoints(this.anchor,this.cursor),this.$silent=!1,this.$cursorChanged&&this._emit("changeCursor"),(this.$cursorChanged||this.$anchorChanged||i!=this.$isEmpty||s)&&this._emit("changeSelection")},this.$moveSelection=function(e){var t=this.lead;this.$isEmpty&&this.setSelectionAnchor(t.row,t.column),e.call(this)},this.selectTo=function(e,t){this.$moveSelection(function(){this.moveCursorTo(e,t)})},this.selectToPosition=function(e){this.$moveSelection(function(){this.moveCursorToPosition(e)})},this.moveTo=function(e,t){this.clearSelection(),this.moveCursorTo(e,t)},this.moveToPosition=function(e){this.clearSelection(),this.moveCursorToPosition(e)},this.selectUp=function(){this.$moveSelection(this.moveCursorUp)},this.selectDown=function(){this.$moveSelection(this.moveCursorDown)},this.selectRight=function(){this.$moveSelection(this.moveCursorRight)},this.selectLeft=function(){this.$moveSelection(this.moveCursorLeft)},this.selectLineStart=function(){this.$moveSelection(this.moveCursorLineStart)},this.selectLineEnd=function(){this.$moveSelection(this.moveCursorLineEnd)},this.selectFileEnd=function(){this.$moveSelection(this.moveCursorFileEnd)},this.selectFileStart=function(){this.$moveSelection(this.moveCursorFileStart)},this.selectWordRight=function(){this.$moveSelection(this.moveCursorWordRight)},this.selectWordLeft=function(){this.$moveSelection(this.moveCursorWordLeft)},this.getWordRange=function(e,t){if(typeof t=="undefined"){var n=e||this.lead;e=n.row,t=n.column}return this.session.getWordRange(e,t)},this.selectWord=function(){this.setSelectionRange(this.getWordRange())},this.selectAWord=function(){var e=this.getCursor(),t=this.session.getAWordRange(e.row,e.column);this.setSelectionRange(t)},this.getLineRange=function(e,t){var n=typeof e=="number"?e:this.lead.row,r,i=this.session.getFoldLine(n);return i?(n=i.start.row,r=i.end.row):r=n,t===!0?new o(n,0,r,this.session.getLine(r).length):new o(n,0,r+1,0)},this.selectLine=function(){this.setSelectionRange(this.getLineRange())},this.moveCursorUp=function(){this.moveCursorBy(-1,0)},this.moveCursorDown=function(){this.moveCursorBy(1,0)},this.wouldMoveIntoSoftTab=function(e,t,n){var r=e.column,i=e.column+t;return n<0&&(r=e.column-t,i=e.column),this.session.isTabStop(e)&&this.doc.getLine(e.row).slice(r,i).split(" ").length-1==t},this.moveCursorLeft=function(){var e=this.lead.getPosition(),t;if(t=this.session.getFoldAt(e.row,e.column,-1))this.moveCursorTo(t.start.row,t.start.column);else if(e.column===0)e.row>0&&this.moveCursorTo(e.row-1,this.doc.getLine(e.row-1).length);else{var n=this.session.getTabSize();this.wouldMoveIntoSoftTab(e,n,-1)&&!this.session.getNavigateWithinSoftTabs()?this.moveCursorBy(0,-n):this.moveCursorBy(0,-1)}},this.moveCursorRight=function(){var e=this.lead.getPosition(),t;if(t=this.session.getFoldAt(e.row,e.column,1))this.moveCursorTo(t.end.row,t.end.column);else if(this.lead.column==this.doc.getLine(this.lead.row).length)this.lead.row0&&(t.column=r)}}this.moveCursorTo(t.row,t.column)},this.moveCursorFileEnd=function(){var e=this.doc.getLength()-1,t=this.doc.getLine(e).length;this.moveCursorTo(e,t)},this.moveCursorFileStart=function(){this.moveCursorTo(0,0)},this.moveCursorLongWordRight=function(){var e=this.lead.row,t=this.lead.column,n=this.doc.getLine(e),r=n.substring(t);this.session.nonTokenRe.lastIndex=0,this.session.tokenRe.lastIndex=0;var i=this.session.getFoldAt(e,t,1);if(i){this.moveCursorTo(i.end.row,i.end.column);return}this.session.nonTokenRe.exec(r)&&(t+=this.session.nonTokenRe.lastIndex,this.session.nonTokenRe.lastIndex=0,r=n.substring(t));if(t>=n.length){this.moveCursorTo(e,n.length),this.moveCursorRight(),e0&&this.moveCursorWordLeft();return}this.session.tokenRe.exec(s)&&(t-=this.session.tokenRe.lastIndex,this.session.tokenRe.lastIndex=0),this.moveCursorTo(e,t)},this.$shortWordEndIndex=function(e){var t=0,n,r=/\s/,i=this.session.tokenRe;i.lastIndex=0;if(this.session.tokenRe.exec(e))t=this.session.tokenRe.lastIndex;else{while((n=e[t])&&r.test(n))t++;if(t<1){i.lastIndex=0;while((n=e[t])&&!i.test(n)){i.lastIndex=0,t++;if(r.test(n)){if(t>2){t--;break}while((n=e[t])&&r.test(n))t++;if(t>2)break}}}}return i.lastIndex=0,t},this.moveCursorShortWordRight=function(){var e=this.lead.row,t=this.lead.column,n=this.doc.getLine(e),r=n.substring(t),i=this.session.getFoldAt(e,t,1);if(i)return this.moveCursorTo(i.end.row,i.end.column);if(t==n.length){var s=this.doc.getLength();do e++,r=this.doc.getLine(e);while(e0&&/^\s*$/.test(r));t=r.length,/\s+$/.test(r)||(r="")}var s=i.stringReverse(r),o=this.$shortWordEndIndex(s);return this.moveCursorTo(e,t-o)},this.moveCursorWordRight=function(){this.session.$selectLongWords?this.moveCursorLongWordRight():this.moveCursorShortWordRight()},this.moveCursorWordLeft=function(){this.session.$selectLongWords?this.moveCursorLongWordLeft():this.moveCursorShortWordLeft()},this.moveCursorBy=function(e,t){var n=this.session.documentToScreenPosition(this.lead.row,this.lead.column),r;t===0&&(e!==0&&(this.session.$bidiHandler.isBidiRow(n.row,this.lead.row)?(r=this.session.$bidiHandler.getPosLeft(n.column),n.column=Math.round(r/this.session.$bidiHandler.charWidths[0])):r=n.column*this.session.$bidiHandler.charWidths[0]),this.$desiredColumn?n.column=this.$desiredColumn:this.$desiredColumn=n.column);if(e!=0&&this.session.lineWidgets&&this.session.lineWidgets[this.lead.row]){var i=this.session.lineWidgets[this.lead.row];e<0?e-=i.rowsAbove||0:e>0&&(e+=i.rowCount-(i.rowsAbove||0))}var s=this.session.screenToDocumentPosition(n.row+e,n.column,r);e!==0&&t===0&&s.row===this.lead.row&&s.column===this.lead.column,this.moveCursorTo(s.row,s.column+t,t===0)},this.moveCursorToPosition=function(e){this.moveCursorTo(e.row,e.column)},this.moveCursorTo=function(e,t,n){var r=this.session.getFoldAt(e,t,1);r&&(e=r.start.row,t=r.start.column),this.$keepDesiredColumnOnChange=!0;var i=this.session.getLine(e);/[\uDC00-\uDFFF]/.test(i.charAt(t))&&i.charAt(t-1)&&(this.lead.row==e&&this.lead.column==t+1?t-=1:t+=1),this.lead.setPosition(e,t),this.$keepDesiredColumnOnChange=!1,n||(this.$desiredColumn=null)},this.moveCursorToScreen=function(e,t,n){var r=this.session.screenToDocumentPosition(e,t);this.moveCursorTo(r.row,r.column,n)},this.detach=function(){this.lead.detach(),this.anchor.detach()},this.fromOrientedRange=function(e){this.setSelectionRange(e,e.cursor==e.start),this.$desiredColumn=e.desiredColumn||this.$desiredColumn},this.toOrientedRange=function(e){var t=this.getRange();return e?(e.start.column=t.start.column,e.start.row=t.start.row,e.end.column=t.end.column,e.end.row=t.end.row):e=t,e.cursor=this.isBackwards()?e.start:e.end,e.desiredColumn=this.$desiredColumn,e},this.getRangeOfMovements=function(e){var t=this.getCursor();try{e(this);var n=this.getCursor();return o.fromPoints(t,n)}catch(r){return o.fromPoints(t,t)}finally{this.moveCursorToPosition(t)}},this.toJSON=function(){if(this.rangeCount)var e=this.ranges.map(function(e){var t=e.clone();return t.isBackwards=e.cursor==e.start,t});else{var e=this.getRange();e.isBackwards=this.isBackwards()}return e},this.fromJSON=function(e){if(e.start==undefined){if(this.rangeList&&e.length>1){this.toSingleRange(e[0]);for(var t=e.length;t--;){var n=o.fromPoints(e[t].start,e[t].end);e[t].isBackwards&&(n.cursor=n.start),this.addRange(n,!0)}return}e=e[0]}this.rangeList&&this.toSingleRange(e),this.setSelectionRange(e,e.isBackwards)},this.isEqual=function(e){if((e.length||this.rangeCount)&&e.length!=this.rangeCount)return!1;if(!e.length||!this.ranges)return this.getRange().isEqual(e);for(var t=this.ranges.length;t--;)if(!this.ranges[t].isEqual(e[t]))return!1;return!0}}).call(u.prototype),t.Selection=u}),define("ace/tokenizer",["require","exports","module","ace/config"],function(e,t,n){"use strict";var r=e("./config"),i=2e3,s=function(e){this.states=e,this.regExps={},this.matchMappings={};for(var t in this.states){var n=this.states[t],r=[],i=0,s=this.matchMappings[t]={defaultToken:"text"},o="g",u=[];for(var a=0;a1?f.onMatch=this.$applyToken:f.onMatch=f.token),c>1&&(/\\\d/.test(f.regex)?l=f.regex.replace(/\\([0-9]+)/g,function(e,t){return"\\"+(parseInt(t,10)+i+1)}):(c=1,l=this.removeCapturingGroups(f.regex)),!f.splitRegex&&typeof f.token!="string"&&u.push(f)),s[i]=a,i+=c,r.push(l),f.onMatch||(f.onMatch=null)}r.length||(s[0]=0,r.push("$")),u.forEach(function(e){e.splitRegex=this.createSplitterRegexp(e.regex,o)},this),this.regExps[t]=new RegExp("("+r.join(")|(")+")|($)",o)}};(function(){this.$setMaxTokenCount=function(e){i=e|0},this.$applyToken=function(e){var t=this.splitRegex.exec(e).slice(1),n=this.token.apply(this,t);if(typeof n=="string")return[{type:n,value:e}];var r=[];for(var i=0,s=n.length;il){var g=e.substring(l,m-v.length);h.type==p?h.value+=g:(h.type&&f.push(h),h={type:p,value:g})}for(var y=0;yi){c>2*e.length&&this.reportError("infinite loop with in ace tokenizer",{startState:t,line:e});while(l1&&n[0]!==r&&n.unshift("#tmp",r),{tokens:f,state:n.length?n:r}},this.reportError=r.reportError}).call(s.prototype),t.Tokenizer=s}),define("ace/mode/text_highlight_rules",["require","exports","module","ace/lib/lang"],function(e,t,n){"use strict";var r=e("../lib/lang"),i=function(){this.$rules={start:[{token:"empty_line",regex:"^$"},{defaultToken:"text"}]}};(function(){this.addRules=function(e,t){if(!t){for(var n in e)this.$rules[n]=e[n];return}for(var n in e){var r=e[n];for(var i=0;i=this.$rowTokens.length){this.$row+=1,e||(e=this.$session.getLength());if(this.$row>=e)return this.$row=e-1,null;this.$rowTokens=this.$session.getTokens(this.$row),this.$tokenIndex=0}return this.$rowTokens[this.$tokenIndex]},this.getCurrentToken=function(){return this.$rowTokens[this.$tokenIndex]},this.getCurrentTokenRow=function(){return this.$row},this.getCurrentTokenColumn=function(){var e=this.$rowTokens,t=this.$tokenIndex,n=e[t].start;if(n!==undefined)return n;n=0;while(t>0)t-=1,n+=e[t].value.length;return n},this.getCurrentTokenPosition=function(){return{row:this.$row,column:this.getCurrentTokenColumn()}},this.getCurrentTokenRange=function(){var e=this.$rowTokens[this.$tokenIndex],t=this.getCurrentTokenColumn();return new r(this.$row,t,this.$row,t+e.value.length)}}).call(i.prototype),t.TokenIterator=i}),define("ace/mode/behaviour/cstyle",["require","exports","module","ace/lib/oop","ace/mode/behaviour","ace/token_iterator","ace/lib/lang"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("../behaviour").Behaviour,s=e("../../token_iterator").TokenIterator,o=e("../../lib/lang"),u=["text","paren.rparen","rparen","paren","punctuation.operator"],a=["text","paren.rparen","rparen","paren","punctuation.operator","comment"],f,l={},c={'"':'"',"'":"'"},h=function(e){var t=-1;e.multiSelect&&(t=e.selection.index,l.rangeCount!=e.multiSelect.rangeCount&&(l={rangeCount:e.multiSelect.rangeCount}));if(l[t])return f=l[t];f=l[t]={autoInsertedBrackets:0,autoInsertedRow:-1,autoInsertedLineEnd:"",maybeInsertedBrackets:0,maybeInsertedRow:-1,maybeInsertedLineStart:"",maybeInsertedLineEnd:""}},p=function(e,t,n,r){var i=e.end.row-e.start.row;return{text:n+t+r,selection:[0,e.start.column+1,i,e.end.column+(i?0:1)]}},d=function(e){this.add("braces","insertion",function(t,n,r,i,s){var u=r.getCursorPosition(),a=i.doc.getLine(u.row);if(s=="{"){h(r);var l=r.getSelectionRange(),c=i.doc.getTextRange(l);if(c!==""&&c!=="{"&&r.getWrapBehavioursEnabled())return p(l,c,"{","}");if(d.isSaneInsertion(r,i))return/[\]\}\)]/.test(a[u.column])||r.inMultiSelectMode||e&&e.braces?(d.recordAutoInsert(r,i,"}"),{text:"{}",selection:[1,1]}):(d.recordMaybeInsert(r,i,"{"),{text:"{",selection:[1,1]})}else if(s=="}"){h(r);var v=a.substring(u.column,u.column+1);if(v=="}"){var m=i.$findOpeningBracket("}",{column:u.column+1,row:u.row});if(m!==null&&d.isAutoInsertedClosing(u,a,s))return d.popAutoInsertedClosing(),{text:"",selection:[1,1]}}}else{if(s=="\n"||s=="\r\n"){h(r);var g="";d.isMaybeInsertedClosing(u,a)&&(g=o.stringRepeat("}",f.maybeInsertedBrackets),d.clearMaybeInsertedClosing());var v=a.substring(u.column,u.column+1);if(v==="}"){var y=i.findMatchingBracket({row:u.row,column:u.column+1},"}");if(!y)return null;var b=this.$getIndent(i.getLine(y.row))}else{if(!g){d.clearMaybeInsertedClosing();return}var b=this.$getIndent(a)}var w=b+i.getTabString();return{text:"\n"+w+"\n"+b+g,selection:[1,w.length,1,w.length]}}d.clearMaybeInsertedClosing()}}),this.add("braces","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&s=="{"){h(n);var o=r.doc.getLine(i.start.row),u=o.substring(i.end.column,i.end.column+1);if(u=="}")return i.end.column++,i;f.maybeInsertedBrackets--}}),this.add("parens","insertion",function(e,t,n,r,i){if(i=="("){h(n);var s=n.getSelectionRange(),o=r.doc.getTextRange(s);if(o!==""&&n.getWrapBehavioursEnabled())return p(s,o,"(",")");if(d.isSaneInsertion(n,r))return d.recordAutoInsert(n,r,")"),{text:"()",selection:[1,1]}}else if(i==")"){h(n);var u=n.getCursorPosition(),a=r.doc.getLine(u.row),f=a.substring(u.column,u.column+1);if(f==")"){var l=r.$findOpeningBracket(")",{column:u.column+1,row:u.row});if(l!==null&&d.isAutoInsertedClosing(u,a,i))return d.popAutoInsertedClosing(),{text:"",selection:[1,1]}}}}),this.add("parens","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&s=="("){h(n);var o=r.doc.getLine(i.start.row),u=o.substring(i.start.column+1,i.start.column+2);if(u==")")return i.end.column++,i}}),this.add("brackets","insertion",function(e,t,n,r,i){if(i=="["){h(n);var s=n.getSelectionRange(),o=r.doc.getTextRange(s);if(o!==""&&n.getWrapBehavioursEnabled())return p(s,o,"[","]");if(d.isSaneInsertion(n,r))return d.recordAutoInsert(n,r,"]"),{text:"[]",selection:[1,1]}}else if(i=="]"){h(n);var u=n.getCursorPosition(),a=r.doc.getLine(u.row),f=a.substring(u.column,u.column+1);if(f=="]"){var l=r.$findOpeningBracket("]",{column:u.column+1,row:u.row});if(l!==null&&d.isAutoInsertedClosing(u,a,i))return d.popAutoInsertedClosing(),{text:"",selection:[1,1]}}}}),this.add("brackets","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&s=="["){h(n);var o=r.doc.getLine(i.start.row),u=o.substring(i.start.column+1,i.start.column+2);if(u=="]")return i.end.column++,i}}),this.add("string_dquotes","insertion",function(e,t,n,r,i){var s=r.$mode.$quotes||c;if(i.length==1&&s[i]){if(this.lineCommentStart&&this.lineCommentStart.indexOf(i)!=-1)return;h(n);var o=i,u=n.getSelectionRange(),a=r.doc.getTextRange(u);if(a!==""&&(a.length!=1||!s[a])&&n.getWrapBehavioursEnabled())return p(u,a,o,o);if(!a){var f=n.getCursorPosition(),l=r.doc.getLine(f.row),d=l.substring(f.column-1,f.column),v=l.substring(f.column,f.column+1),m=r.getTokenAt(f.row,f.column),g=r.getTokenAt(f.row,f.column+1);if(d=="\\"&&m&&/escape/.test(m.type))return null;var y=m&&/string|escape/.test(m.type),b=!g||/string|escape/.test(g.type),w;if(v==o)w=y!==b,w&&/string\.end/.test(g.type)&&(w=!1);else{if(y&&!b)return null;if(y&&b)return null;var E=r.$mode.tokenRe;E.lastIndex=0;var S=E.test(d);E.lastIndex=0;var x=E.test(d);if(S||x)return null;if(v&&!/[\s;,.})\]\\]/.test(v))return null;var T=l[f.column-2];if(!(d!=o||T!=o&&!E.test(T)))return null;w=!0}return{text:w?o+o:"",selection:[1,1]}}}}),this.add("string_dquotes","deletion",function(e,t,n,r,i){var s=r.$mode.$quotes||c,o=r.doc.getTextRange(i);if(!i.isMultiLine()&&s.hasOwnProperty(o)){h(n);var u=r.doc.getLine(i.start.row),a=u.substring(i.start.column+1,i.start.column+2);if(a==o)return i.end.column++,i}})};d.isSaneInsertion=function(e,t){var n=e.getCursorPosition(),r=new s(t,n.row,n.column);if(!this.$matchTokenType(r.getCurrentToken()||"text",u)){if(/[)}\]]/.test(e.session.getLine(n.row)[n.column]))return!0;var i=new s(t,n.row,n.column+1);if(!this.$matchTokenType(i.getCurrentToken()||"text",u))return!1}return r.stepForward(),r.getCurrentTokenRow()!==n.row||this.$matchTokenType(r.getCurrentToken()||"text",a)},d.$matchTokenType=function(e,t){return t.indexOf(e.type||e)>-1},d.recordAutoInsert=function(e,t,n){var r=e.getCursorPosition(),i=t.doc.getLine(r.row);this.isAutoInsertedClosing(r,i,f.autoInsertedLineEnd[0])||(f.autoInsertedBrackets=0),f.autoInsertedRow=r.row,f.autoInsertedLineEnd=n+i.substr(r.column),f.autoInsertedBrackets++},d.recordMaybeInsert=function(e,t,n){var r=e.getCursorPosition(),i=t.doc.getLine(r.row);this.isMaybeInsertedClosing(r,i)||(f.maybeInsertedBrackets=0),f.maybeInsertedRow=r.row,f.maybeInsertedLineStart=i.substr(0,r.column)+n,f.maybeInsertedLineEnd=i.substr(r.column),f.maybeInsertedBrackets++},d.isAutoInsertedClosing=function(e,t,n){return f.autoInsertedBrackets>0&&e.row===f.autoInsertedRow&&n===f.autoInsertedLineEnd[0]&&t.substr(e.column)===f.autoInsertedLineEnd},d.isMaybeInsertedClosing=function(e,t){return f.maybeInsertedBrackets>0&&e.row===f.maybeInsertedRow&&t.substr(e.column)===f.maybeInsertedLineEnd&&t.substr(0,e.column)==f.maybeInsertedLineStart},d.popAutoInsertedClosing=function(){f.autoInsertedLineEnd=f.autoInsertedLineEnd.substr(1),f.autoInsertedBrackets--},d.clearMaybeInsertedClosing=function(){f&&(f.maybeInsertedBrackets=0,f.maybeInsertedRow=-1)},r.inherits(d,i),t.CstyleBehaviour=d}),define("ace/unicode",["require","exports","module"],function(e,t,n){"use strict";var r=[48,9,8,25,5,0,2,25,48,0,11,0,5,0,6,22,2,30,2,457,5,11,15,4,8,0,2,0,18,116,2,1,3,3,9,0,2,2,2,0,2,19,2,82,2,138,2,4,3,155,12,37,3,0,8,38,10,44,2,0,2,1,2,1,2,0,9,26,6,2,30,10,7,61,2,9,5,101,2,7,3,9,2,18,3,0,17,58,3,100,15,53,5,0,6,45,211,57,3,18,2,5,3,11,3,9,2,1,7,6,2,2,2,7,3,1,3,21,2,6,2,0,4,3,3,8,3,1,3,3,9,0,5,1,2,4,3,11,16,2,2,5,5,1,3,21,2,6,2,1,2,1,2,1,3,0,2,4,5,1,3,2,4,0,8,3,2,0,8,15,12,2,2,8,2,2,2,21,2,6,2,1,2,4,3,9,2,2,2,2,3,0,16,3,3,9,18,2,2,7,3,1,3,21,2,6,2,1,2,4,3,8,3,1,3,2,9,1,5,1,2,4,3,9,2,0,17,1,2,5,4,2,2,3,4,1,2,0,2,1,4,1,4,2,4,11,5,4,4,2,2,3,3,0,7,0,15,9,18,2,2,7,2,2,2,22,2,9,2,4,4,7,2,2,2,3,8,1,2,1,7,3,3,9,19,1,2,7,2,2,2,22,2,9,2,4,3,8,2,2,2,3,8,1,8,0,2,3,3,9,19,1,2,7,2,2,2,22,2,15,4,7,2,2,2,3,10,0,9,3,3,9,11,5,3,1,2,17,4,23,2,8,2,0,3,6,4,0,5,5,2,0,2,7,19,1,14,57,6,14,2,9,40,1,2,0,3,1,2,0,3,0,7,3,2,6,2,2,2,0,2,0,3,1,2,12,2,2,3,4,2,0,2,5,3,9,3,1,35,0,24,1,7,9,12,0,2,0,2,0,5,9,2,35,5,19,2,5,5,7,2,35,10,0,58,73,7,77,3,37,11,42,2,0,4,328,2,3,3,6,2,0,2,3,3,40,2,3,3,32,2,3,3,6,2,0,2,3,3,14,2,56,2,3,3,66,5,0,33,15,17,84,13,619,3,16,2,25,6,74,22,12,2,6,12,20,12,19,13,12,2,2,2,1,13,51,3,29,4,0,5,1,3,9,34,2,3,9,7,87,9,42,6,69,11,28,4,11,5,11,11,39,3,4,12,43,5,25,7,10,38,27,5,62,2,28,3,10,7,9,14,0,89,75,5,9,18,8,13,42,4,11,71,55,9,9,4,48,83,2,2,30,14,230,23,280,3,5,3,37,3,5,3,7,2,0,2,0,2,0,2,30,3,52,2,6,2,0,4,2,2,6,4,3,3,5,5,12,6,2,2,6,67,1,20,0,29,0,14,0,17,4,60,12,5,0,4,11,18,0,5,0,3,9,2,0,4,4,7,0,2,0,2,0,2,3,2,10,3,3,6,4,5,0,53,1,2684,46,2,46,2,132,7,6,15,37,11,53,10,0,17,22,10,6,2,6,2,6,2,6,2,6,2,6,2,6,2,6,2,31,48,0,470,1,36,5,2,4,6,1,5,85,3,1,3,2,2,89,2,3,6,40,4,93,18,23,57,15,513,6581,75,20939,53,1164,68,45,3,268,4,27,21,31,3,13,13,1,2,24,9,69,11,1,38,8,3,102,3,1,111,44,25,51,13,68,12,9,7,23,4,0,5,45,3,35,13,28,4,64,15,10,39,54,10,13,3,9,7,22,4,1,5,66,25,2,227,42,2,1,3,9,7,11171,13,22,5,48,8453,301,3,61,3,105,39,6,13,4,6,11,2,12,2,4,2,0,2,1,2,1,2,107,34,362,19,63,3,53,41,11,5,15,17,6,13,1,25,2,33,4,2,134,20,9,8,25,5,0,2,25,12,88,4,5,3,5,3,5,3,2],i=0,s=[];for(var o=0;o2?r%f!=f-1:r%f==0}}var E=Infinity;w(function(e,t){var n=e.search(/\S/);n!==-1?(ne.length&&(E=e.length)}),u==Infinity&&(u=E,s=!1,o=!1),l&&u%f!=0&&(u=Math.floor(u/f)*f),w(o?m:v)},this.toggleBlockComment=function(e,t,n,r){var i=this.blockComment;if(!i)return;!i.start&&i[0]&&(i=i[0]);var s=new f(t,r.row,r.column),o=s.getCurrentToken(),u=t.selection,a=t.selection.toOrientedRange(),c,h;if(o&&/comment/.test(o.type)){var p,d;while(o&&/comment/.test(o.type)){var v=o.value.indexOf(i.start);if(v!=-1){var m=s.getCurrentTokenRow(),g=s.getCurrentTokenColumn()+v;p=new l(m,g,m,g+i.start.length);break}o=s.stepBackward()}var s=new f(t,r.row,r.column),o=s.getCurrentToken();while(o&&/comment/.test(o.type)){var v=o.value.indexOf(i.end);if(v!=-1){var m=s.getCurrentTokenRow(),g=s.getCurrentTokenColumn()+v;d=new l(m,g,m,g+i.end.length);break}o=s.stepForward()}d&&t.remove(d),p&&(t.remove(p),c=p.start.row,h=-i.start.length)}else h=i.start.length,c=n.start.row,t.insert(n.end,i.end),t.insert(n.start,i.start);a.start.row==c&&(a.start.column+=h),a.end.row==c&&(a.end.column+=h),t.selection.fromOrientedRange(a)},this.getNextLineIndent=function(e,t,n){return this.$getIndent(t)},this.checkOutdent=function(e,t,n){return!1},this.autoOutdent=function(e,t,n){},this.$getIndent=function(e){return e.match(/^\s*/)[0]},this.createWorker=function(e){return null},this.createModeDelegates=function(e){this.$embeds=[],this.$modes={};for(var t in e)if(e[t]){var n=e[t],i=n.prototype.$id,s=r.$modes[i];s||(r.$modes[i]=s=new n),r.$modes[t]||(r.$modes[t]=s),this.$embeds.push(t),this.$modes[t]=s}var o=["toggleBlockComment","toggleCommentLines","getNextLineIndent","checkOutdent","autoOutdent","transformAction","getCompletions"];for(var t=0;t=0&&t.row=0&&t.column<=e[t.row].length}function s(e,t){t.action!="insert"&&t.action!="remove"&&r(t,"delta.action must be 'insert' or 'remove'"),t.lines instanceof Array||r(t,"delta.lines must be an Array"),(!t.start||!t.end)&&r(t,"delta.start/end must be an present");var n=t.start;i(e,t.start)||r(t,"delta.start must be contained in document");var s=t.end;t.action=="remove"&&!i(e,s)&&r(t,"delta.end must contained in document for 'remove' actions");var o=s.row-n.row,u=s.column-(o==0?n.column:0);(o!=t.lines.length-1||t.lines[o].length!=u)&&r(t,"delta.range must match delta lines")}t.applyDelta=function(e,t,n){var r=t.start.row,i=t.start.column,s=e[r]||"";switch(t.action){case"insert":var o=t.lines;if(o.length===1)e[r]=s.substring(0,i)+t.lines[0]+s.substring(i);else{var u=[r,1].concat(t.lines);e.splice.apply(e,u),e[r]=s.substring(0,i)+e[r],e[r+t.lines.length-1]+=s.substring(i)}break;case"remove":var a=t.end.column,f=t.end.row;r===f?e[r]=s.substring(0,i)+s.substring(a):e.splice(r,f-r+1,s.substring(0,i)+e[f].substring(a))}}}),define("ace/anchor",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/event_emitter").EventEmitter,s=t.Anchor=function(e,t,n){this.$onChange=this.onChange.bind(this),this.attach(e),typeof n=="undefined"?this.setPosition(t.row,t.column):this.setPosition(t,n)};(function(){function e(e,t,n){var r=n?e.column<=t.column:e.columnthis.row)return;var n=t(e,{row:this.row,column:this.column},this.$insertRight);this.setPosition(n.row,n.column,!0)},this.setPosition=function(e,t,n){var r;n?r={row:e,column:t}:r=this.$clipPositionToDocument(e,t);if(this.row==r.row&&this.column==r.column)return;var i={row:this.row,column:this.column};this.row=r.row,this.column=r.column,this._signal("change",{old:i,value:r})},this.detach=function(){this.document.off("change",this.$onChange)},this.attach=function(e){this.document=e||this.document,this.document.on("change",this.$onChange)},this.$clipPositionToDocument=function(e,t){var n={};return e>=this.document.getLength()?(n.row=Math.max(0,this.document.getLength()-1),n.column=this.document.getLine(n.row).length):e<0?(n.row=0,n.column=0):(n.row=e,n.column=Math.min(this.document.getLine(n.row).length,Math.max(0,t))),t<0&&(n.column=0),n}}).call(s.prototype)}),define("ace/document",["require","exports","module","ace/lib/oop","ace/apply_delta","ace/lib/event_emitter","ace/range","ace/anchor"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./apply_delta").applyDelta,s=e("./lib/event_emitter").EventEmitter,o=e("./range").Range,u=e("./anchor").Anchor,a=function(e){this.$lines=[""],e.length===0?this.$lines=[""]:Array.isArray(e)?this.insertMergedLines({row:0,column:0},e):this.insert({row:0,column:0},e)};(function(){r.implement(this,s),this.setValue=function(e){var t=this.getLength()-1;this.remove(new o(0,0,t,this.getLine(t).length)),this.insert({row:0,column:0},e)},this.getValue=function(){return this.getAllLines().join(this.getNewLineCharacter())},this.createAnchor=function(e,t){return new u(this,e,t)},"aaa".split(/a/).length===0?this.$split=function(e){return e.replace(/\r\n|\r/g,"\n").split("\n")}:this.$split=function(e){return e.split(/\r\n|\r|\n/)},this.$detectNewLine=function(e){var t=e.match(/^.*?(\r\n|\r|\n)/m);this.$autoNewLine=t?t[1]:"\n",this._signal("changeNewLineMode")},this.getNewLineCharacter=function(){switch(this.$newLineMode){case"windows":return"\r\n";case"unix":return"\n";default:return this.$autoNewLine||"\n"}},this.$autoNewLine="",this.$newLineMode="auto",this.setNewLineMode=function(e){if(this.$newLineMode===e)return;this.$newLineMode=e,this._signal("changeNewLineMode")},this.getNewLineMode=function(){return this.$newLineMode},this.isNewLine=function(e){return e=="\r\n"||e=="\r"||e=="\n"},this.getLine=function(e){return this.$lines[e]||""},this.getLines=function(e,t){return this.$lines.slice(e,t+1)},this.getAllLines=function(){return this.getLines(0,this.getLength())},this.getLength=function(){return this.$lines.length},this.getTextRange=function(e){return this.getLinesForRange(e).join(this.getNewLineCharacter())},this.getLinesForRange=function(e){var t;if(e.start.row===e.end.row)t=[this.getLine(e.start.row).substring(e.start.column,e.end.column)];else{t=this.getLines(e.start.row,e.end.row),t[0]=(t[0]||"").substring(e.start.column);var n=t.length-1;e.end.row-e.start.row==n&&(t[n]=t[n].substring(0,e.end.column))}return t},this.insertLines=function(e,t){return console.warn("Use of document.insertLines is deprecated. Use the insertFullLines method instead."),this.insertFullLines(e,t)},this.removeLines=function(e,t){return console.warn("Use of document.removeLines is deprecated. Use the removeFullLines method instead."),this.removeFullLines(e,t)},this.insertNewLine=function(e){return console.warn("Use of document.insertNewLine is deprecated. Use insertMergedLines(position, ['', '']) instead."),this.insertMergedLines(e,["",""])},this.insert=function(e,t){return this.getLength()<=1&&this.$detectNewLine(t),this.insertMergedLines(e,this.$split(t))},this.insertInLine=function(e,t){var n=this.clippedPos(e.row,e.column),r=this.pos(e.row,e.column+t.length);return this.applyDelta({start:n,end:r,action:"insert",lines:[t]},!0),this.clonePos(r)},this.clippedPos=function(e,t){var n=this.getLength();e===undefined?e=n:e<0?e=0:e>=n&&(e=n-1,t=undefined);var r=this.getLine(e);return t==undefined&&(t=r.length),t=Math.min(Math.max(t,0),r.length),{row:e,column:t}},this.clonePos=function(e){return{row:e.row,column:e.column}},this.pos=function(e,t){return{row:e,column:t}},this.$clipPosition=function(e){var t=this.getLength();return e.row>=t?(e.row=Math.max(0,t-1),e.column=this.getLine(t-1).length):(e.row=Math.max(0,e.row),e.column=Math.min(Math.max(e.column,0),this.getLine(e.row).length)),e},this.insertFullLines=function(e,t){e=Math.min(Math.max(e,0),this.getLength());var n=0;e0,r=t=0&&this.applyDelta({start:this.pos(e,this.getLine(e).length),end:this.pos(e+1,0),action:"remove",lines:["",""]})},this.replace=function(e,t){e instanceof o||(e=o.fromPoints(e.start,e.end));if(t.length===0&&e.isEmpty())return e.start;if(t==this.getTextRange(e))return e.end;this.remove(e);var n;return t?n=this.insert(e.start,t):n=e.start,n},this.applyDeltas=function(e){for(var t=0;t=0;t--)this.revertDelta(e[t])},this.applyDelta=function(e,t){var n=e.action=="insert";if(n?e.lines.length<=1&&!e.lines[0]:!o.comparePoints(e.start,e.end))return;n&&e.lines.length>2e4?this.$splitAndapplyLargeDelta(e,2e4):(i(this.$lines,e,t),this._signal("change",e))},this.$safeApplyDelta=function(e){var t=this.$lines.length;(e.action=="remove"&&e.start.row20){n.running=setTimeout(n.$worker,20);break}}n.currentLine=t,r==-1&&(r=t),s<=r&&n.fireUpdateEvent(s,r)}};(function(){r.implement(this,i),this.setTokenizer=function(e){this.tokenizer=e,this.lines=[],this.states=[],this.start(0)},this.setDocument=function(e){this.doc=e,this.lines=[],this.states=[],this.stop()},this.fireUpdateEvent=function(e,t){var n={first:e,last:t};this._signal("update",{data:n})},this.start=function(e){this.currentLine=Math.min(e||0,this.currentLine,this.doc.getLength()),this.lines.splice(this.currentLine,this.lines.length),this.states.splice(this.currentLine,this.states.length),this.stop(),this.running=setTimeout(this.$worker,700)},this.scheduleStart=function(){this.running||(this.running=setTimeout(this.$worker,700))},this.$updateOnChange=function(e){var t=e.start.row,n=e.end.row-t;if(n===0)this.lines[t]=null;else if(e.action=="remove")this.lines.splice(t,n+1,null),this.states.splice(t,n+1,null);else{var r=Array(n+1);r.unshift(t,1),this.lines.splice.apply(this.lines,r),this.states.splice.apply(this.states,r)}this.currentLine=Math.min(t,this.currentLine,this.doc.getLength()),this.stop()},this.stop=function(){this.running&&clearTimeout(this.running),this.running=!1},this.getTokens=function(e){return this.lines[e]||this.$tokenizeRow(e)},this.getState=function(e){return this.currentLine==e&&this.$tokenizeRow(e),this.states[e]||"start"},this.$tokenizeRow=function(e){var t=this.doc.getLine(e),n=this.states[e-1],r=this.tokenizer.getLineTokens(t,n,e);return this.states[e]+""!=r.state+""?(this.states[e]=r.state,this.lines[e+1]=null,this.currentLine>e+1&&(this.currentLine=e+1)):this.currentLine==e&&(this.currentLine=e+1),this.lines[e]=r.tokens}}).call(s.prototype),t.BackgroundTokenizer=s}),define("ace/search_highlight",["require","exports","module","ace/lib/lang","ace/lib/oop","ace/range"],function(e,t,n){"use strict";var r=e("./lib/lang"),i=e("./lib/oop"),s=e("./range").Range,o=function(e,t,n){this.setRegexp(e),this.clazz=t,this.type=n||"text"};(function(){this.MAX_RANGES=500,this.setRegexp=function(e){if(this.regExp+""==e+"")return;this.regExp=e,this.cache=[]},this.update=function(e,t,n,i){if(!this.regExp)return;var o=i.firstRow,u=i.lastRow;for(var a=o;a<=u;a++){var f=this.cache[a];f==null&&(f=r.getMatchOffsets(n.getLine(a),this.regExp),f.length>this.MAX_RANGES&&(f=f.slice(0,this.MAX_RANGES)),f=f.map(function(e){return new s(a,e.offset,a,e.offset+e.length)}),this.cache[a]=f.length?f:"");for(var l=f.length;l--;)t.drawSingleLineMarker(e,f[l].toScreenRange(n),this.clazz,i)}}}).call(o.prototype),t.SearchHighlight=o}),define("ace/edit_session/fold_line",["require","exports","module","ace/range"],function(e,t,n){"use strict";function i(e,t){this.foldData=e,Array.isArray(t)?this.folds=t:t=this.folds=[t];var n=t[t.length-1];this.range=new r(t[0].start.row,t[0].start.column,n.end.row,n.end.column),this.start=this.range.start,this.end=this.range.end,this.folds.forEach(function(e){e.setFoldLine(this)},this)}var r=e("../range").Range;(function(){this.shiftRow=function(e){this.start.row+=e,this.end.row+=e,this.folds.forEach(function(t){t.start.row+=e,t.end.row+=e})},this.addFold=function(e){if(e.sameRow){if(e.start.rowthis.endRow)throw new Error("Can't add a fold to this FoldLine as it has no connection");this.folds.push(e),this.folds.sort(function(e,t){return-e.range.compareEnd(t.start.row,t.start.column)}),this.range.compareEnd(e.start.row,e.start.column)>0?(this.end.row=e.end.row,this.end.column=e.end.column):this.range.compareStart(e.end.row,e.end.column)<0&&(this.start.row=e.start.row,this.start.column=e.start.column)}else if(e.start.row==this.end.row)this.folds.push(e),this.end.row=e.end.row,this.end.column=e.end.column;else{if(e.end.row!=this.start.row)throw new Error("Trying to add fold to FoldRow that doesn't have a matching row");this.folds.unshift(e),this.start.row=e.start.row,this.start.column=e.start.column}e.foldLine=this},this.containsRow=function(e){return e>=this.start.row&&e<=this.end.row},this.walk=function(e,t,n){var r=0,i=this.folds,s,o,u,a=!0;t==null&&(t=this.end.row,n=this.end.column);for(var f=0;f0)continue;var a=i(e,o.start);return u===0?t&&a!==0?-s-2:s:a>0||a===0&&!t?s:-s-1}return-s-1},this.add=function(e){var t=!e.isEmpty(),n=this.pointIndex(e.start,t);n<0&&(n=-n-1);var r=this.pointIndex(e.end,t,n);return r<0?r=-r-1:r++,this.ranges.splice(n,r-n,e)},this.addList=function(e){var t=[];for(var n=e.length;n--;)t.push.apply(t,this.add(e[n]));return t},this.substractPoint=function(e){var t=this.pointIndex(e);if(t>=0)return this.ranges.splice(t,1)},this.merge=function(){var e=[],t=this.ranges;t=t.sort(function(e,t){return i(e.start,t.start)});var n=t[0],r;for(var s=1;s=0},this.containsPoint=function(e){return this.pointIndex(e)>=0},this.rangeAtPoint=function(e){var t=this.pointIndex(e);if(t>=0)return this.ranges[t]},this.clipRows=function(e,t){var n=this.ranges;if(n[0].start.row>t||n[n.length-1].start.row=r)break}if(e.action=="insert"){var f=i-r,l=-t.column+n.column;for(;or)break;a.start.row==r&&a.start.column>=t.column&&(a.start.column==t.column&&this.$bias<=0||(a.start.column+=l,a.start.row+=f));if(a.end.row==r&&a.end.column>=t.column){if(a.end.column==t.column&&this.$bias<0)continue;a.end.column==t.column&&l>0&&oa.start.column&&a.end.column==s[o+1].start.column&&(a.end.column-=l),a.end.column+=l,a.end.row+=f}}}else{var f=r-i,l=t.column-n.column;for(;oi)break;if(a.end.rowt.column)a.end.column=t.column,a.end.row=t.row}else a.end.column+=l,a.end.row+=f;else a.end.row>i&&(a.end.row+=f);if(a.start.rowt.column)a.start.column=t.column,a.start.row=t.row}else a.start.column+=l,a.start.row+=f;else a.start.row>i&&(a.start.row+=f)}}if(f!=0&&o=e)return i;if(i.end.row>e)return null}return null},this.getNextFoldLine=function(e,t){var n=this.$foldData,r=0;t&&(r=n.indexOf(t)),r==-1&&(r=0);for(r;r=e)return i}return null},this.getFoldedRowCount=function(e,t){var n=this.$foldData,r=t-e+1;for(var i=0;i=t){u=e?r-=t-u:r=0);break}o>=e&&(u>=e?r-=o-u:r-=o-e+1)}return r},this.$addFoldLine=function(e){return this.$foldData.push(e),this.$foldData.sort(function(e,t){return e.start.row-t.start.row}),e},this.addFold=function(e,t){var n=this.$foldData,r=!1,o;e instanceof s?o=e:(o=new s(t,e),o.collapseChildren=t.collapseChildren),this.$clipRangeToDocument(o.range);var u=o.start.row,a=o.start.column,f=o.end.row,l=o.end.column,c=this.getFoldAt(u,a,1),h=this.getFoldAt(f,l,-1);if(c&&h==c)return c.addSubFold(o);c&&!c.range.isStart(u,a)&&this.removeFold(c),h&&!h.range.isEnd(f,l)&&this.removeFold(h);var p=this.getFoldsInRange(o.range);p.length>0&&(this.removeFolds(p),o.collapseChildren||p.forEach(function(e){o.addSubFold(e)}));for(var d=0;d0&&this.foldAll(e.start.row+1,e.end.row,e.collapseChildren-1),e.subFolds=[]},this.expandFolds=function(e){e.forEach(function(e){this.expandFold(e)},this)},this.unfold=function(e,t){var n,i;if(e==null)n=new r(0,0,this.getLength(),0),t==null&&(t=!0);else if(typeof e=="number")n=new r(e,0,e,this.getLine(e).length);else if("row"in e)n=r.fromPoints(e,e);else{if(Array.isArray(e))return i=[],e.forEach(function(e){i=i.concat(this.unfold(e))},this),i;n=e}i=this.getFoldsInRangeList(n);var s=i;while(i.length==1&&r.comparePoints(i[0].start,n.start)<0&&r.comparePoints(i[0].end,n.end)>0)this.expandFolds(i),i=this.getFoldsInRangeList(n);t!=0?this.removeFolds(i):this.expandFolds(i);if(s.length)return s},this.isRowFolded=function(e,t){return!!this.getFoldLine(e,t)},this.getRowFoldEnd=function(e,t){var n=this.getFoldLine(e,t);return n?n.end.row:e},this.getRowFoldStart=function(e,t){var n=this.getFoldLine(e,t);return n?n.start.row:e},this.getFoldDisplayLine=function(e,t,n,r,i){r==null&&(r=e.start.row),i==null&&(i=0),t==null&&(t=e.end.row),n==null&&(n=this.getLine(t).length);var s=this.doc,o="";return e.walk(function(e,t,n,u){if(tl)break}while(s&&a.test(s.type));s=i.stepBackward()}else s=i.getCurrentToken();return f.end.row=i.getCurrentTokenRow(),f.end.column=i.getCurrentTokenColumn()+s.value.length-2,f}},this.foldAll=function(e,t,n,r){n==undefined&&(n=1e5);var i=this.foldWidgets;if(!i)return;t=t||this.getLength(),e=e||0;for(var s=e;s=e&&(s=o.end.row,o.collapseChildren=n,this.addFold("...",o))}},this.foldToLevel=function(e){this.foldAll();while(e-->0)this.unfold(null,!1)},this.foldAllComments=function(){var e=this;this.foldAll(null,null,null,function(t){var n=e.getTokens(t);for(var r=0;r=0){var s=n[r];s==null&&(s=n[r]=this.getFoldWidget(r));if(s=="start"){var o=this.getFoldWidgetRange(r);i||(i=o);if(o&&o.end.row>=e)break}r--}return{range:r!==-1&&o,firstRange:i}},this.onFoldWidgetClick=function(e,t){t=t.domEvent;var n={children:t.shiftKey,all:t.ctrlKey||t.metaKey,siblings:t.altKey},r=this.$toggleFoldWidget(e,n);if(!r){var i=t.target||t.srcElement;i&&/ace_fold-widget/.test(i.className)&&(i.className+=" ace_invalid")}},this.$toggleFoldWidget=function(e,t){if(!this.getFoldWidget)return;var n=this.getFoldWidget(e),r=this.getLine(e),i=n==="end"?-1:1,s=this.getFoldAt(e,i===-1?0:r.length,i);if(s)return t.children||t.all?this.removeFold(s):this.expandFold(s),s;var o=this.getFoldWidgetRange(e,!0);if(o&&!o.isMultiLine()){s=this.getFoldAt(o.start.row,o.start.column,1);if(s&&o.isEqual(s.range))return this.removeFold(s),s}if(t.siblings){var u=this.getParentFoldRangeData(e);if(u.range)var a=u.range.start.row+1,f=u.range.end.row;this.foldAll(a,f,t.all?1e4:0)}else t.children?(f=o?o.end.row:this.getLength(),this.foldAll(e+1,f,t.all?1e4:0)):o&&(t.all&&(o.collapseChildren=1e4),this.addFold("...",o));return o},this.toggleFoldWidget=function(e){var t=this.selection.getCursor().row;t=this.getRowFoldStart(t);var n=this.$toggleFoldWidget(t,{});if(n)return;var r=this.getParentFoldRangeData(t,!0);n=r.range||r.firstRange;if(n){t=n.start.row;var i=this.getFoldAt(t,this.getLine(t).length,1);i?this.removeFold(i):this.addFold("...",n)}},this.updateFoldWidgets=function(e){var t=e.start.row,n=e.end.row-t;if(n===0)this.foldWidgets[t]=null;else if(e.action=="remove")this.foldWidgets.splice(t,n+1,null);else{var r=Array(n+1);r.unshift(t,1),this.foldWidgets.splice.apply(this.foldWidgets,r)}},this.tokenizerUpdateFoldWidgets=function(e){var t=e.data;t.first!=t.last&&this.foldWidgets.length>t.first&&this.foldWidgets.splice(t.first,this.foldWidgets.length)}}var r=e("../range").Range,i=e("./fold_line").FoldLine,s=e("./fold").Fold,o=e("../token_iterator").TokenIterator;t.Folding=u}),define("ace/edit_session/bracket_match",["require","exports","module","ace/token_iterator","ace/range"],function(e,t,n){"use strict";function s(){this.findMatchingBracket=function(e,t){if(e.column==0)return null;var n=t||this.getLine(e.row).charAt(e.column-1);if(n=="")return null;var r=n.match(/([\(\[\{])|([\)\]\}])/);return r?r[1]?this.$findClosingBracket(r[1],e):this.$findOpeningBracket(r[2],e):null},this.getBracketRange=function(e){var t=this.getLine(e.row),n=!0,r,s=t.charAt(e.column-1),o=s&&s.match(/([\(\[\{])|([\)\]\}])/);o||(s=t.charAt(e.column),e={row:e.row,column:e.column+1},o=s&&s.match(/([\(\[\{])|([\)\]\}])/),n=!1);if(!o)return null;if(o[1]){var u=this.$findClosingBracket(o[1],e);if(!u)return null;r=i.fromPoints(e,u),n||(r.end.column++,r.start.column--),r.cursor=r.end}else{var u=this.$findOpeningBracket(o[2],e);if(!u)return null;r=i.fromPoints(u,e),n||(r.start.column++,r.end.column--),r.cursor=r.start}return r},this.getMatchingBracketRanges=function(e){var t=this.getLine(e.row),n=t.charAt(e.column-1),r=n&&n.match(/([\(\[\{])|([\)\]\}])/);r||(n=t.charAt(e.column),e={row:e.row,column:e.column+1},r=n&&n.match(/([\(\[\{])|([\)\]\}])/));if(!r)return null;var s=new i(e.row,e.column-1,e.row,e.column),o=r[1]?this.$findClosingBracket(r[1],e):this.$findOpeningBracket(r[2],e);if(!o)return[s];var u=new i(o.row,o.column,o.row,o.column+1);return[s,u]},this.$brackets={")":"(","(":")","]":"[","[":"]","{":"}","}":"{","<":">",">":"<"},this.$findOpeningBracket=function(e,t,n){var i=this.$brackets[e],s=1,o=new r(this,t.row,t.column),u=o.getCurrentToken();u||(u=o.stepForward());if(!u)return;n||(n=new RegExp("(\\.?"+u.type.replace(".","\\.").replace("rparen",".paren").replace(/\b(?:end)\b/,"(?:start|begin|end)")+")+"));var a=t.column-o.getCurrentTokenColumn()-2,f=u.value;for(;;){while(a>=0){var l=f.charAt(a);if(l==i){s-=1;if(s==0)return{row:o.getCurrentTokenRow(),column:a+o.getCurrentTokenColumn()}}else l==e&&(s+=1);a-=1}do u=o.stepBackward();while(u&&!n.test(u.type));if(u==null)break;f=u.value,a=f.length-1}return null},this.$findClosingBracket=function(e,t,n){var i=this.$brackets[e],s=1,o=new r(this,t.row,t.column),u=o.getCurrentToken();u||(u=o.stepForward());if(!u)return;n||(n=new RegExp("(\\.?"+u.type.replace(".","\\.").replace("lparen",".paren").replace(/\b(?:start|begin)\b/,"(?:start|begin|end)")+")+"));var a=t.column-o.getCurrentTokenColumn();for(;;){var f=u.value,l=f.length;while(a=4352&&e<=4447||e>=4515&&e<=4519||e>=4602&&e<=4607||e>=9001&&e<=9002||e>=11904&&e<=11929||e>=11931&&e<=12019||e>=12032&&e<=12245||e>=12272&&e<=12283||e>=12288&&e<=12350||e>=12353&&e<=12438||e>=12441&&e<=12543||e>=12549&&e<=12589||e>=12593&&e<=12686||e>=12688&&e<=12730||e>=12736&&e<=12771||e>=12784&&e<=12830||e>=12832&&e<=12871||e>=12880&&e<=13054||e>=13056&&e<=19903||e>=19968&&e<=42124||e>=42128&&e<=42182||e>=43360&&e<=43388||e>=44032&&e<=55203||e>=55216&&e<=55238||e>=55243&&e<=55291||e>=63744&&e<=64255||e>=65040&&e<=65049||e>=65072&&e<=65106||e>=65108&&e<=65126||e>=65128&&e<=65131||e>=65281&&e<=65376||e>=65504&&e<=65510}r.implement(this,u),this.setDocument=function(e){this.doc&&this.doc.off("change",this.$onChange),this.doc=e,e.on("change",this.$onChange),this.bgTokenizer&&this.bgTokenizer.setDocument(this.getDocument()),this.resetCaches()},this.getDocument=function(){return this.doc},this.$resetRowCache=function(e){if(!e){this.$docRowCache=[],this.$screenRowCache=[];return}var t=this.$docRowCache.length,n=this.$getRowCacheIndex(this.$docRowCache,e)+1;t>n&&(this.$docRowCache.splice(n,t),this.$screenRowCache.splice(n,t))},this.$getRowCacheIndex=function(e,t){var n=0,r=e.length-1;while(n<=r){var i=n+r>>1,s=e[i];if(t>s)n=i+1;else{if(!(t=t)break}return r=n[s],r?(r.index=s,r.start=i-r.value.length,r):null},this.setUndoManager=function(e){this.$undoManager=e,this.$informUndoManager&&this.$informUndoManager.cancel();if(e){var t=this;e.addSession(this),this.$syncInformUndoManager=function(){t.$informUndoManager.cancel(),t.mergeUndoDeltas=!1},this.$informUndoManager=i.delayedCall(this.$syncInformUndoManager)}else this.$syncInformUndoManager=function(){}},this.markUndoGroup=function(){this.$syncInformUndoManager&&this.$syncInformUndoManager()},this.$defaultUndoManager={undo:function(){},redo:function(){},hasUndo:function(){},hasRedo:function(){},reset:function(){},add:function(){},addSelection:function(){},startNewGroup:function(){},addSession:function(){}},this.getUndoManager=function(){return this.$undoManager||this.$defaultUndoManager},this.getTabString=function(){return this.getUseSoftTabs()?i.stringRepeat(" ",this.getTabSize()):" "},this.setUseSoftTabs=function(e){this.setOption("useSoftTabs",e)},this.getUseSoftTabs=function(){return this.$useSoftTabs&&!this.$mode.$indentWithTabs},this.setTabSize=function(e){this.setOption("tabSize",e)},this.getTabSize=function(){return this.$tabSize},this.isTabStop=function(e){return this.$useSoftTabs&&e.column%this.$tabSize===0},this.setNavigateWithinSoftTabs=function(e){this.setOption("navigateWithinSoftTabs",e)},this.getNavigateWithinSoftTabs=function(){return this.$navigateWithinSoftTabs},this.$overwrite=!1,this.setOverwrite=function(e){this.setOption("overwrite",e)},this.getOverwrite=function(){return this.$overwrite},this.toggleOverwrite=function(){this.setOverwrite(!this.$overwrite)},this.addGutterDecoration=function(e,t){this.$decorations[e]||(this.$decorations[e]=""),this.$decorations[e]+=" "+t,this._signal("changeBreakpoint",{})},this.removeGutterDecoration=function(e,t){this.$decorations[e]=(this.$decorations[e]||"").replace(" "+t,""),this._signal("changeBreakpoint",{})},this.getBreakpoints=function(){return this.$breakpoints},this.setBreakpoints=function(e){this.$breakpoints=[];for(var t=0;t0&&(r=!!n.charAt(t-1).match(this.tokenRe)),r||(r=!!n.charAt(t).match(this.tokenRe));if(r)var i=this.tokenRe;else if(/^\s+$/.test(n.slice(t-1,t+1)))var i=/\s/;else var i=this.nonTokenRe;var s=t;if(s>0){do s--;while(s>=0&&n.charAt(s).match(i));s++}var o=t;while(oe&&(e=t.screenWidth)}),this.lineWidgetWidth=e},this.$computeWidth=function(e){if(this.$modified||e){this.$modified=!1;if(this.$useWrapMode)return this.screenWidth=this.$wrapLimit;var t=this.doc.getAllLines(),n=this.$rowLengthCache,r=0,i=0,s=this.$foldData[i],o=s?s.start.row:Infinity,u=t.length;for(var a=0;ao){a=s.end.row+1;if(a>=u)break;s=this.$foldData[i++],o=s?s.start.row:Infinity}n[a]==null&&(n[a]=this.$getStringScreenWidth(t[a])[0]),n[a]>r&&(r=n[a])}this.screenWidth=r}},this.getLine=function(e){return this.doc.getLine(e)},this.getLines=function(e,t){return this.doc.getLines(e,t)},this.getLength=function(){return this.doc.getLength()},this.getTextRange=function(e){return this.doc.getTextRange(e||this.selection.getRange())},this.insert=function(e,t){return this.doc.insert(e,t)},this.remove=function(e){return this.doc.remove(e)},this.removeFullLines=function(e,t){return this.doc.removeFullLines(e,t)},this.undoChanges=function(e,t){if(!e.length)return;this.$fromUndo=!0;for(var n=e.length-1;n!=-1;n--){var r=e[n];r.action=="insert"||r.action=="remove"?this.doc.revertDelta(r):r.folds&&this.addFolds(r.folds)}!t&&this.$undoSelect&&(e.selectionBefore?this.selection.fromJSON(e.selectionBefore):this.selection.setRange(this.$getUndoSelection(e,!0))),this.$fromUndo=!1},this.redoChanges=function(e,t){if(!e.length)return;this.$fromUndo=!0;for(var n=0;ne.end.column&&(s.start.column+=u),s.end.row==e.end.row&&s.end.column>e.end.column&&(s.end.column+=u)),o&&s.start.row>=e.end.row&&(s.start.row+=o,s.end.row+=o)}s.end=this.insert(s.start,r);if(i.length){var a=e.start,f=s.start,o=f.row-a.row,u=f.column-a.column;this.addFolds(i.map(function(e){return e=e.clone(),e.start.row==a.row&&(e.start.column+=u),e.end.row==a.row&&(e.end.column+=u),e.start.row+=o,e.end.row+=o,e}))}return s},this.indentRows=function(e,t,n){n=n.replace(/\t/g,this.getTabString());for(var r=e;r<=t;r++)this.doc.insertInLine({row:r,column:0},n)},this.outdentRows=function(e){var t=e.collapseRows(),n=new l(0,0,0,0),r=this.getTabSize();for(var i=t.start.row;i<=t.end.row;++i){var s=this.getLine(i);n.start.row=i,n.end.row=i;for(var o=0;o0){var r=this.getRowFoldEnd(t+n);if(r>this.doc.getLength()-1)return 0;var i=r-t}else{e=this.$clipRowToDocument(e),t=this.$clipRowToDocument(t);var i=t-e+1}var s=new l(e,0,t,Number.MAX_VALUE),o=this.getFoldsInRange(s).map(function(e){return e=e.clone(),e.start.row+=i,e.end.row+=i,e}),u=n==0?this.doc.getLines(e,t):this.doc.removeFullLines(e,t);return this.doc.insertFullLines(e+i,u),o.length&&this.addFolds(o),i},this.moveLinesUp=function(e,t){return this.$moveLines(e,t,-1)},this.moveLinesDown=function(e,t){return this.$moveLines(e,t,1)},this.duplicateLines=function(e,t){return this.$moveLines(e,t,0)},this.$clipRowToDocument=function(e){return Math.max(0,Math.min(e,this.doc.getLength()-1))},this.$clipColumnToRow=function(e,t){return t<0?0:Math.min(this.doc.getLine(e).length,t)},this.$clipPositionToDocument=function(e,t){t=Math.max(0,t);if(e<0)e=0,t=0;else{var n=this.doc.getLength();e>=n?(e=n-1,t=this.doc.getLine(n-1).length):t=Math.min(this.doc.getLine(e).length,t)}return{row:e,column:t}},this.$clipRangeToDocument=function(e){e.start.row<0?(e.start.row=0,e.start.column=0):e.start.column=this.$clipColumnToRow(e.start.row,e.start.column);var t=this.doc.getLength()-1;return e.end.row>t?(e.end.row=t,e.end.column=this.doc.getLine(t).length):e.end.column=this.$clipColumnToRow(e.end.row,e.end.column),e},this.$wrapLimit=80,this.$useWrapMode=!1,this.$wrapLimitRange={min:null,max:null},this.setUseWrapMode=function(e){if(e!=this.$useWrapMode){this.$useWrapMode=e,this.$modified=!0,this.$resetRowCache(0);if(e){var t=this.getLength();this.$wrapData=Array(t),this.$updateWrapData(0,t-1)}this._signal("changeWrapMode")}},this.getUseWrapMode=function(){return this.$useWrapMode},this.setWrapLimitRange=function(e,t){if(this.$wrapLimitRange.min!==e||this.$wrapLimitRange.max!==t)this.$wrapLimitRange={min:e,max:t},this.$modified=!0,this.$bidiHandler.markAsDirty(),this.$useWrapMode&&this._signal("changeWrapMode")},this.adjustWrapLimit=function(e,t){var n=this.$wrapLimitRange;n.max<0&&(n={min:t,max:t});var r=this.$constrainWrapLimit(e,n.min,n.max);return r!=this.$wrapLimit&&r>1?(this.$wrapLimit=r,this.$modified=!0,this.$useWrapMode&&(this.$updateWrapData(0,this.getLength()-1),this.$resetRowCache(0),this._signal("changeWrapLimit")),!0):!1},this.$constrainWrapLimit=function(e,t,n){return t&&(e=Math.max(t,e)),n&&(e=Math.min(n,e)),e},this.getWrapLimit=function(){return this.$wrapLimit},this.setWrapLimit=function(e){this.setWrapLimitRange(e,e)},this.getWrapLimitRange=function(){return{min:this.$wrapLimitRange.min,max:this.$wrapLimitRange.max}},this.$updateInternalDataOnChange=function(e){var t=this.$useWrapMode,n=e.action,r=e.start,i=e.end,s=r.row,o=i.row,u=o-s,a=null;this.$updating=!0;if(u!=0)if(n==="remove"){this[t?"$wrapData":"$rowLengthCache"].splice(s,u);var f=this.$foldData;a=this.getFoldsInRange(e),this.removeFolds(a);var l=this.getFoldLine(i.row),c=0;if(l){l.addRemoveChars(i.row,i.column,r.column-i.column),l.shiftRow(-u);var h=this.getFoldLine(s);h&&h!==l&&(h.merge(l),l=h),c=f.indexOf(l)+1}for(c;c=i.row&&l.shiftRow(-u)}o=s}else{var p=Array(u);p.unshift(s,0);var d=t?this.$wrapData:this.$rowLengthCache;d.splice.apply(d,p);var f=this.$foldData,l=this.getFoldLine(s),c=0;if(l){var v=l.range.compareInside(r.row,r.column);v==0?(l=l.split(r.row,r.column),l&&(l.shiftRow(u),l.addRemoveChars(o,0,i.column-r.column))):v==-1&&(l.addRemoveChars(s,0,i.column-r.column),l.shiftRow(u)),c=f.indexOf(l)+1}for(c;c=s&&l.shiftRow(u)}}else{u=Math.abs(e.start.column-e.end.column),n==="remove"&&(a=this.getFoldsInRange(e),this.removeFolds(a),u=-u);var l=this.getFoldLine(s);l&&l.addRemoveChars(s,r.column,u)}return t&&this.$wrapData.length!=this.doc.getLength()&&console.error("doc.getLength() and $wrapData.length have to be the same!"),this.$updating=!1,t?this.$updateWrapData(s,o):this.$updateRowLengthCache(s,o),a},this.$updateRowLengthCache=function(e,t,n){this.$rowLengthCache[e]=null,this.$rowLengthCache[t]=null},this.$updateWrapData=function(e,t){var r=this.doc.getAllLines(),i=this.getTabSize(),o=this.$wrapData,u=this.$wrapLimit,a,f,l=e;t=Math.min(t,r.length-1);while(l<=t)f=this.getFoldLine(l,f),f?(a=[],f.walk(function(e,t,i,o){var u;if(e!=null){u=this.$getDisplayTokens(e,a.length),u[0]=n;for(var f=1;fr-b){var w=f+r-b;if(e[w-1]>=c&&e[w]>=c){y(w);continue}if(e[w]==n||e[w]==s){for(w;w!=f-1;w--)if(e[w]==n)break;if(w>f){y(w);continue}w=f+r;for(w;w>2)),f-1);while(w>E&&e[w]E&&e[w]E&&e[w]==a)w--}else while(w>E&&e[w]E){y(++w);continue}w=f+r,e[w]==t&&w--,y(w-b)}return o},this.$getDisplayTokens=function(n,r){var i=[],s;r=r||0;for(var o=0;o39&&u<48||u>57&&u<64?i.push(a):u>=4352&&m(u)?i.push(e,t):i.push(e)}return i},this.$getStringScreenWidth=function(e,t,n){if(t==0)return[0,0];t==null&&(t=Infinity),n=n||0;var r,i;for(i=0;i=4352&&m(r)?n+=2:n+=1;if(n>t)break}return[n,i]},this.lineWidgets=null,this.getRowLength=function(e){var t=1;return this.lineWidgets&&(t+=this.lineWidgets[e]&&this.lineWidgets[e].rowCount||0),!this.$useWrapMode||!this.$wrapData[e]?t:this.$wrapData[e].length+t},this.getRowLineCount=function(e){return!this.$useWrapMode||!this.$wrapData[e]?1:this.$wrapData[e].length+1},this.getRowWrapIndent=function(e){if(this.$useWrapMode){var t=this.screenToDocumentPosition(e,Number.MAX_VALUE),n=this.$wrapData[t.row];return n.length&&n[0]=0)var u=f[l],i=this.$docRowCache[l],h=e>f[c-1];else var h=!c;var p=this.getLength()-1,d=this.getNextFoldLine(i),v=d?d.start.row:Infinity;while(u<=e){a=this.getRowLength(i);if(u+a>e||i>=p)break;u+=a,i++,i>v&&(i=d.end.row+1,d=this.getNextFoldLine(i,d),v=d?d.start.row:Infinity),h&&(this.$docRowCache.push(i),this.$screenRowCache.push(u))}if(d&&d.start.row<=i)r=this.getFoldDisplayLine(d),i=d.start.row;else{if(u+a<=e||i>p)return{row:p,column:this.getLine(p).length};r=this.getLine(i),d=null}var m=0,g=Math.floor(e-u);if(this.$useWrapMode){var y=this.$wrapData[i];y&&(o=y[g],g>0&&y.length&&(m=y.indent,s=y[g-1]||y[y.length-1],r=r.substring(s)))}return n!==undefined&&this.$bidiHandler.isBidiRow(u+g,i,g)&&(t=this.$bidiHandler.offsetToCol(n)),s+=this.$getStringScreenWidth(r,t-m)[1],this.$useWrapMode&&s>=o&&(s=o-1),d?d.idxToPosition(s):{row:i,column:s}},this.documentToScreenPosition=function(e,t){if(typeof t=="undefined")var n=this.$clipPositionToDocument(e.row,e.column);else n=this.$clipPositionToDocument(e,t);e=n.row,t=n.column;var r=0,i=null,s=null;s=this.getFoldAt(e,t,1),s&&(e=s.start.row,t=s.start.column);var o,u=0,a=this.$docRowCache,f=this.$getRowCacheIndex(a,e),l=a.length;if(l&&f>=0)var u=a[f],r=this.$screenRowCache[f],c=e>a[l-1];else var c=!l;var h=this.getNextFoldLine(u),p=h?h.start.row:Infinity;while(u=p){o=h.end.row+1;if(o>e)break;h=this.getNextFoldLine(o,h),p=h?h.start.row:Infinity}else o=u+1;r+=this.getRowLength(u),u=o,c&&(this.$docRowCache.push(u),this.$screenRowCache.push(r))}var d="";h&&u>=p?(d=this.getFoldDisplayLine(h,e,t),i=h.start.row):(d=this.getLine(e).substring(0,t),i=e);var v=0;if(this.$useWrapMode){var m=this.$wrapData[i];if(m){var g=0;while(d.length>=m[g])r++,g++;d=d.substring(m[g-1]||0,d.length),v=g>0?m.indent:0}}return this.lineWidgets&&this.lineWidgets[u]&&this.lineWidgets[u].rowsAbove&&(r+=this.lineWidgets[u].rowsAbove),{row:r,column:v+this.$getStringScreenWidth(d)[0]}},this.documentToScreenColumn=function(e,t){return this.documentToScreenPosition(e,t).column},this.documentToScreenRow=function(e,t){return this.documentToScreenPosition(e,t).row},this.getScreenLength=function(){var e=0,t=null;if(!this.$useWrapMode){e=this.getLength();var n=this.$foldData;for(var r=0;ro&&(s=t.end.row+1,t=this.$foldData[r++],o=t?t.start.row:Infinity)}}return this.lineWidgets&&(e+=this.$getWidgetScreenLength()),e},this.$setFontMetrics=function(e){if(!this.$enableVarChar)return;this.$getStringScreenWidth=function(t,n,r){if(n===0)return[0,0];n||(n=Infinity),r=r||0;var i,s;for(s=0;sn)break}return[r,s]}},this.destroy=function(){this.bgTokenizer&&(this.bgTokenizer.setDocument(null),this.bgTokenizer=null),this.$stopWorker(),this.removeAllListeners(),this.doc&&this.doc.off("change",this.$onChange),this.selection.detach()},this.isFullWidth=m}.call(d.prototype),e("./edit_session/folding").Folding.call(d.prototype),e("./edit_session/bracket_match").BracketMatch.call(d.prototype),o.defineOptions(d.prototype,"session",{wrap:{set:function(e){!e||e=="off"?e=!1:e=="free"?e=!0:e=="printMargin"?e=-1:typeof e=="string"&&(e=parseInt(e,10)||!1);if(this.$wrap==e)return;this.$wrap=e;if(!e)this.setUseWrapMode(!1);else{var t=typeof e=="number"?e:null;this.setWrapLimitRange(t,t),this.setUseWrapMode(!0)}},get:function(){return this.getUseWrapMode()?this.$wrap==-1?"printMargin":this.getWrapLimitRange().min?this.$wrap:"free":"off"},handlesSet:!0},wrapMethod:{set:function(e){e=e=="auto"?this.$mode.type!="text":e!="text",e!=this.$wrapAsCode&&(this.$wrapAsCode=e,this.$useWrapMode&&(this.$useWrapMode=!1,this.setUseWrapMode(!0)))},initialValue:"auto"},indentedSoftWrap:{set:function(){this.$useWrapMode&&(this.$useWrapMode=!1,this.setUseWrapMode(!0))},initialValue:!0},firstLineNumber:{set:function(){this._signal("changeBreakpoint")},initialValue:1},useWorker:{set:function(e){this.$useWorker=e,this.$stopWorker(),e&&this.$startWorker()},initialValue:!0},useSoftTabs:{initialValue:!0},tabSize:{set:function(e){e=parseInt(e),e>0&&this.$tabSize!==e&&(this.$modified=!0,this.$rowLengthCache=[],this.$tabSize=e,this._signal("changeTabSize"))},initialValue:4,handlesSet:!0},navigateWithinSoftTabs:{initialValue:!1},foldStyle:{set:function(e){this.setFoldStyle(e)},handlesSet:!0},overwrite:{set:function(e){this._signal("changeOverwrite")},initialValue:!1},newLineMode:{set:function(e){this.doc.setNewLineMode(e)},get:function(){return this.doc.getNewLineMode()},handlesSet:!0},mode:{set:function(e){this.setMode(e)},get:function(){return this.$modeId},handlesSet:!0}}),t.EditSession=d}),define("ace/search",["require","exports","module","ace/lib/lang","ace/lib/oop","ace/range"],function(e,t,n){"use strict";function u(e,t){function n(e){return/\w/.test(e)||t.regExp?"\\b":""}return n(e[0])+e+n(e[e.length-1])}var r=e("./lib/lang"),i=e("./lib/oop"),s=e("./range").Range,o=function(){this.$options={}};(function(){this.set=function(e){return i.mixin(this.$options,e),this},this.getOptions=function(){return r.copyObject(this.$options)},this.setOptions=function(e){this.$options=e},this.find=function(e){var t=this.$options,n=this.$matchIterator(e,t);if(!n)return!1;var r=null;return n.forEach(function(e,n,i,o){return r=new s(e,n,i,o),n==o&&t.start&&t.start.start&&t.skipCurrent!=0&&r.isEqual(t.start)?(r=null,!1):!0}),r},this.findAll=function(e){var t=this.$options;if(!t.needle)return[];this.$assembleRegExp(t);var n=t.range,i=n?e.getLines(n.start.row,n.end.row):e.doc.getAllLines(),o=[],u=t.re;if(t.$isMultiLine){var a=u.length,f=i.length-a,l;e:for(var c=u.offset||0;c<=f;c++){for(var h=0;hv)continue;o.push(l=new s(c,v,c+a-1,m)),a>2&&(c=c+a-2)}}else for(var g=0;gE&&o[h].end.row==n.end.row)h--;o=o.slice(g,h+1);for(g=0,h=o.length;g=u;n--)if(c(n,Number.MAX_VALUE,e))return;if(t.wrap==0)return;for(n=a,u=o.row;n>=u;n--)if(c(n,Number.MAX_VALUE,e))return};else var f=function(e){var n=o.row;if(c(n,o.column,e))return;for(n+=1;n<=a;n++)if(c(n,0,e))return;if(t.wrap==0)return;for(n=u,a=o.row;n<=a;n++)if(c(n,0,e))return};if(t.$isMultiLine)var l=n.length,c=function(t,i,s){var o=r?t-l+1:t;if(o<0||o+l>e.getLength())return;var u=e.getLine(o),a=u.search(n[0]);if(!r&&ai)return;if(s(o,a,o+l-1,c))return!0};else if(r)var c=function(t,r,i){var s=e.getLine(t),o=[],u,a=0;n.lastIndex=0;while(u=n.exec(s)){var f=u[0].length;a=u.index;if(!f){if(a>=s.length)break;n.lastIndex=a+=1}if(u.index+f>r)break;o.push(u.index,f)}for(var l=o.length-1;l>=0;l-=2){var c=o[l-1],f=o[l];if(i(t,c,t,c+f))return!0}};else var c=function(t,r,i){var s=e.getLine(t),o,u;n.lastIndex=r;while(u=n.exec(s)){var a=u[0].length;o=u.index;if(i(t,o,t,o+a))return!0;if(!a){n.lastIndex=o+=1;if(o>=s.length)return!1}}};return{forEach:f}}}).call(o.prototype),t.Search=o}),define("ace/keyboard/hash_handler",["require","exports","module","ace/lib/keys","ace/lib/useragent"],function(e,t,n){"use strict";function o(e,t){this.platform=t||(i.isMac?"mac":"win"),this.commands={},this.commandKeyBinding={},this.addCommands(e),this.$singleCommand=!0}function u(e,t){o.call(this,e,t),this.$singleCommand=!1}var r=e("../lib/keys"),i=e("../lib/useragent"),s=r.KEY_MODS;u.prototype=o.prototype,function(){function e(e){return typeof e=="object"&&e.bindKey&&e.bindKey.position||(e.isDefault?-100:0)}this.addCommand=function(e){this.commands[e.name]&&this.removeCommand(e),this.commands[e.name]=e,e.bindKey&&this._buildKeyHash(e)},this.removeCommand=function(e,t){var n=e&&(typeof e=="string"?e:e.name);e=this.commands[n],t||delete this.commands[n];var r=this.commandKeyBinding;for(var i in r){var s=r[i];if(s==e)delete r[i];else if(Array.isArray(s)){var o=s.indexOf(e);o!=-1&&(s.splice(o,1),s.length==1&&(r[i]=s[0]))}}},this.bindKey=function(e,t,n){typeof e=="object"&&e&&(n==undefined&&(n=e.position),e=e[this.platform]);if(!e)return;if(typeof t=="function")return this.addCommand({exec:t,bindKey:e,name:t.name||e});e.split("|").forEach(function(e){var r="";if(e.indexOf(" ")!=-1){var i=e.split(/\s+/);e=i.pop(),i.forEach(function(e){var t=this.parseKeys(e),n=s[t.hashId]+t.key;r+=(r?" ":"")+n,this._addCommandToBinding(r,"chainKeys")},this),r+=" "}var o=this.parseKeys(e),u=s[o.hashId]+o.key;this._addCommandToBinding(r+u,t,n)},this)},this._addCommandToBinding=function(t,n,r){var i=this.commandKeyBinding,s;if(!n)delete i[t];else if(!i[t]||this.$singleCommand)i[t]=n;else{Array.isArray(i[t])?(s=i[t].indexOf(n))!=-1&&i[t].splice(s,1):i[t]=[i[t]],typeof r!="number"&&(r=e(n));var o=i[t];for(s=0;sr)break}o.splice(s,0,n)}},this.addCommands=function(e){e&&Object.keys(e).forEach(function(t){var n=e[t];if(!n)return;if(typeof n=="string")return this.bindKey(n,t);typeof n=="function"&&(n={exec:n});if(typeof n!="object")return;n.name||(n.name=t),this.addCommand(n)},this)},this.removeCommands=function(e){Object.keys(e).forEach(function(t){this.removeCommand(e[t])},this)},this.bindKeys=function(e){Object.keys(e).forEach(function(t){this.bindKey(t,e[t])},this)},this._buildKeyHash=function(e){this.bindKey(e.bindKey,e)},this.parseKeys=function(e){var t=e.toLowerCase().split(/[\-\+]([\-\+])?/).filter(function(e){return e}),n=t.pop(),i=r[n];if(r.FUNCTION_KEYS[i])n=r.FUNCTION_KEYS[i].toLowerCase();else{if(!t.length)return{key:n,hashId:-1};if(t.length==1&&t[0]=="shift")return{key:n.toUpperCase(),hashId:-1}}var s=0;for(var o=t.length;o--;){var u=r.KEY_MODS[t[o]];if(u==null)return typeof console!="undefined"&&console.error("invalid modifier "+t[o]+" in "+e),!1;s|=u}return{key:n,hashId:s}},this.findKeyCommand=function(t,n){var r=s[t]+n;return this.commandKeyBinding[r]},this.handleKeyboard=function(e,t,n,r){if(r<0)return;var i=s[t]+n,o=this.commandKeyBinding[i];e.$keyChain&&(e.$keyChain+=" "+i,o=this.commandKeyBinding[e.$keyChain]||o);if(o)if(o=="chainKeys"||o[o.length-1]=="chainKeys")return e.$keyChain=e.$keyChain||i,{command:"null"};if(e.$keyChain)if(!!t&&t!=4||n.length!=1){if(t==-1||r>0)e.$keyChain=""}else e.$keyChain=e.$keyChain.slice(0,-i.length-1);return{command:o}},this.getStatusText=function(e,t){return t.$keyChain||""}}.call(o.prototype),t.HashHandler=o,t.MultiHashHandler=u}),define("ace/commands/command_manager",["require","exports","module","ace/lib/oop","ace/keyboard/hash_handler","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("../keyboard/hash_handler").MultiHashHandler,s=e("../lib/event_emitter").EventEmitter,o=function(e,t){i.call(this,t,e),this.byName=this.commands,this.setDefaultHandler("exec",function(e){return e.command.exec(e.editor,e.args||{})})};r.inherits(o,i),function(){r.implement(this,s),this.exec=function(e,t,n){if(Array.isArray(e)){for(var r=e.length;r--;)if(this.exec(e[r],t,n))return!0;return!1}typeof e=="string"&&(e=this.commands[e]);if(!e)return!1;if(t&&t.$readOnly&&!e.readOnly)return!1;if(this.$checkCommandState!=0&&e.isAvailable&&!e.isAvailable(t))return!1;var i={editor:t,command:e,args:n};return i.returnValue=this._emit("exec",i),this._signal("afterExec",i),i.returnValue===!1?!1:!0},this.toggleRecording=function(e){if(this.$inReplay)return;return e&&e._emit("changeStatus"),this.recording?(this.macro.pop(),this.off("exec",this.$addCommandToMacro),this.macro.length||(this.macro=this.oldMacro),this.recording=!1):(this.$addCommandToMacro||(this.$addCommandToMacro=function(e){this.macro.push([e.command,e.args])}.bind(this)),this.oldMacro=this.macro,this.macro=[],this.on("exec",this.$addCommandToMacro),this.recording=!0)},this.replay=function(e){if(this.$inReplay||!this.macro)return;if(this.recording)return this.toggleRecording(e);try{this.$inReplay=!0,this.macro.forEach(function(t){typeof t=="string"?this.exec(t,e):this.exec(t[0],e,t[1])},this)}finally{this.$inReplay=!1}},this.trimMacro=function(e){return e.map(function(e){return typeof e[0]!="string"&&(e[0]=e[0].name),e[1]||(e=e[0]),e})}}.call(o.prototype),t.CommandManager=o}),define("ace/commands/default_commands",["require","exports","module","ace/lib/lang","ace/config","ace/range"],function(e,t,n){"use strict";function o(e,t){return{win:e,mac:t}}var r=e("../lib/lang"),i=e("../config"),s=e("../range").Range;t.commands=[{name:"showSettingsMenu",description:"Show settings menu",bindKey:o("Ctrl-,","Command-,"),exec:function(e){i.loadModule("ace/ext/settings_menu",function(t){t.init(e),e.showSettingsMenu()})},readOnly:!0},{name:"goToNextError",description:"Go to next error",bindKey:o("Alt-E","F4"),exec:function(e){i.loadModule("./ext/error_marker",function(t){t.showErrorMarker(e,1)})},scrollIntoView:"animate",readOnly:!0},{name:"goToPreviousError",description:"Go to previous error",bindKey:o("Alt-Shift-E","Shift-F4"),exec:function(e){i.loadModule("./ext/error_marker",function(t){t.showErrorMarker(e,-1)})},scrollIntoView:"animate",readOnly:!0},{name:"selectall",description:"Select all",bindKey:o("Ctrl-A","Command-A"),exec:function(e){e.selectAll()},readOnly:!0},{name:"centerselection",description:"Center selection",bindKey:o(null,"Ctrl-L"),exec:function(e){e.centerSelection()},readOnly:!0},{name:"gotoline",description:"Go to line...",bindKey:o("Ctrl-L","Command-L"),exec:function(e,t){typeof t=="number"&&!isNaN(t)&&e.gotoLine(t),e.prompt({$type:"gotoLine"})},readOnly:!0},{name:"fold",bindKey:o("Alt-L|Ctrl-F1","Command-Alt-L|Command-F1"),exec:function(e){e.session.toggleFold(!1)},multiSelectAction:"forEach",scrollIntoView:"center",readOnly:!0},{name:"unfold",bindKey:o("Alt-Shift-L|Ctrl-Shift-F1","Command-Alt-Shift-L|Command-Shift-F1"),exec:function(e){e.session.toggleFold(!0)},multiSelectAction:"forEach",scrollIntoView:"center",readOnly:!0},{name:"toggleFoldWidget",description:"Toggle fold widget",bindKey:o("F2","F2"),exec:function(e){e.session.toggleFoldWidget()},multiSelectAction:"forEach",scrollIntoView:"center",readOnly:!0},{name:"toggleParentFoldWidget",description:"Toggle parent fold widget",bindKey:o("Alt-F2","Alt-F2"),exec:function(e){e.session.toggleFoldWidget(!0)},multiSelectAction:"forEach",scrollIntoView:"center",readOnly:!0},{name:"foldall",description:"Fold all",bindKey:o(null,"Ctrl-Command-Option-0"),exec:function(e){e.session.foldAll()},scrollIntoView:"center",readOnly:!0},{name:"foldAllComments",description:"Fold all comments",bindKey:o(null,"Ctrl-Command-Option-0"),exec:function(e){e.session.foldAllComments()},scrollIntoView:"center",readOnly:!0},{name:"foldOther",description:"Fold other",bindKey:o("Alt-0","Command-Option-0"),exec:function(e){e.session.foldAll(),e.session.unfold(e.selection.getAllRanges())},scrollIntoView:"center",readOnly:!0},{name:"unfoldall",description:"Unfold all",bindKey:o("Alt-Shift-0","Command-Option-Shift-0"),exec:function(e){e.session.unfold()},scrollIntoView:"center",readOnly:!0},{name:"findnext",description:"Find next",bindKey:o("Ctrl-K","Command-G"),exec:function(e){e.findNext()},multiSelectAction:"forEach",scrollIntoView:"center",readOnly:!0},{name:"findprevious",description:"Find previous",bindKey:o("Ctrl-Shift-K","Command-Shift-G"),exec:function(e){e.findPrevious()},multiSelectAction:"forEach",scrollIntoView:"center",readOnly:!0},{name:"selectOrFindNext",description:"Select or find next",bindKey:o("Alt-K","Ctrl-G"),exec:function(e){e.selection.isEmpty()?e.selection.selectWord():e.findNext()},readOnly:!0},{name:"selectOrFindPrevious",description:"Select or find previous",bindKey:o("Alt-Shift-K","Ctrl-Shift-G"),exec:function(e){e.selection.isEmpty()?e.selection.selectWord():e.findPrevious()},readOnly:!0},{name:"find",description:"Find",bindKey:o("Ctrl-F","Command-F"),exec:function(e){i.loadModule("ace/ext/searchbox",function(t){t.Search(e)})},readOnly:!0},{name:"overwrite",description:"Overwrite",bindKey:"Insert",exec:function(e){e.toggleOverwrite()},readOnly:!0},{name:"selecttostart",description:"Select to start",bindKey:o("Ctrl-Shift-Home","Command-Shift-Home|Command-Shift-Up"),exec:function(e){e.getSelection().selectFileStart()},multiSelectAction:"forEach",readOnly:!0,scrollIntoView:"animate",aceCommandGroup:"fileJump"},{name:"gotostart",description:"Go to start",bindKey:o("Ctrl-Home","Command-Home|Command-Up"),exec:function(e){e.navigateFileStart()},multiSelectAction:"forEach",readOnly:!0,scrollIntoView:"animate",aceCommandGroup:"fileJump"},{name:"selectup",description:"Select up",bindKey:o("Shift-Up","Shift-Up|Ctrl-Shift-P"),exec:function(e){e.getSelection().selectUp()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"golineup",description:"Go line up",bindKey:o("Up","Up|Ctrl-P"),exec:function(e,t){e.navigateUp(t.times)},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selecttoend",description:"Select to end",bindKey:o("Ctrl-Shift-End","Command-Shift-End|Command-Shift-Down"),exec:function(e){e.getSelection().selectFileEnd()},multiSelectAction:"forEach",readOnly:!0,scrollIntoView:"animate",aceCommandGroup:"fileJump"},{name:"gotoend",description:"Go to end",bindKey:o("Ctrl-End","Command-End|Command-Down"),exec:function(e){e.navigateFileEnd()},multiSelectAction:"forEach",readOnly:!0,scrollIntoView:"animate",aceCommandGroup:"fileJump"},{name:"selectdown",description:"Select down",bindKey:o("Shift-Down","Shift-Down|Ctrl-Shift-N"),exec:function(e){e.getSelection().selectDown()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"golinedown",description:"Go line down",bindKey:o("Down","Down|Ctrl-N"),exec:function(e,t){e.navigateDown(t.times)},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selectwordleft",description:"Select word left",bindKey:o("Ctrl-Shift-Left","Option-Shift-Left"),exec:function(e){e.getSelection().selectWordLeft()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"gotowordleft",description:"Go to word left",bindKey:o("Ctrl-Left","Option-Left"),exec:function(e){e.navigateWordLeft()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selecttolinestart",description:"Select to line start",bindKey:o("Alt-Shift-Left","Command-Shift-Left|Ctrl-Shift-A"),exec:function(e){e.getSelection().selectLineStart()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"gotolinestart",description:"Go to line start",bindKey:o("Alt-Left|Home","Command-Left|Home|Ctrl-A"),exec:function(e){e.navigateLineStart()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selectleft",description:"Select left",bindKey:o("Shift-Left","Shift-Left|Ctrl-Shift-B"),exec:function(e){e.getSelection().selectLeft()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"gotoleft",description:"Go to left",bindKey:o("Left","Left|Ctrl-B"),exec:function(e,t){e.navigateLeft(t.times)},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selectwordright",description:"Select word right",bindKey:o("Ctrl-Shift-Right","Option-Shift-Right"),exec:function(e){e.getSelection().selectWordRight()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"gotowordright",description:"Go to word right",bindKey:o("Ctrl-Right","Option-Right"),exec:function(e){e.navigateWordRight()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selecttolineend",description:"Select to line end",bindKey:o("Alt-Shift-Right","Command-Shift-Right|Shift-End|Ctrl-Shift-E"),exec:function(e){e.getSelection().selectLineEnd()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"gotolineend",description:"Go to line end",bindKey:o("Alt-Right|End","Command-Right|End|Ctrl-E"),exec:function(e){e.navigateLineEnd()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selectright",description:"Select right",bindKey:o("Shift-Right","Shift-Right"),exec:function(e){e.getSelection().selectRight()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"gotoright",description:"Go to right",bindKey:o("Right","Right|Ctrl-F"),exec:function(e,t){e.navigateRight(t.times)},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selectpagedown",description:"Select page down",bindKey:"Shift-PageDown",exec:function(e){e.selectPageDown()},readOnly:!0},{name:"pagedown",description:"Page down",bindKey:o(null,"Option-PageDown"),exec:function(e){e.scrollPageDown()},readOnly:!0},{name:"gotopagedown",description:"Go to page down",bindKey:o("PageDown","PageDown|Ctrl-V"),exec:function(e){e.gotoPageDown()},readOnly:!0},{name:"selectpageup",description:"Select page up",bindKey:"Shift-PageUp",exec:function(e){e.selectPageUp()},readOnly:!0},{name:"pageup",description:"Page up",bindKey:o(null,"Option-PageUp"),exec:function(e){e.scrollPageUp()},readOnly:!0},{name:"gotopageup",description:"Go to page up",bindKey:"PageUp",exec:function(e){e.gotoPageUp()},readOnly:!0},{name:"scrollup",description:"Scroll up",bindKey:o("Ctrl-Up",null),exec:function(e){e.renderer.scrollBy(0,-2*e.renderer.layerConfig.lineHeight)},readOnly:!0},{name:"scrolldown",description:"Scroll down",bindKey:o("Ctrl-Down",null),exec:function(e){e.renderer.scrollBy(0,2*e.renderer.layerConfig.lineHeight)},readOnly:!0},{name:"selectlinestart",description:"Select line start",bindKey:"Shift-Home",exec:function(e){e.getSelection().selectLineStart()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selectlineend",description:"Select line end",bindKey:"Shift-End",exec:function(e){e.getSelection().selectLineEnd()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"togglerecording",description:"Toggle recording",bindKey:o("Ctrl-Alt-E","Command-Option-E"),exec:function(e){e.commands.toggleRecording(e)},readOnly:!0},{name:"replaymacro",description:"Replay macro",bindKey:o("Ctrl-Shift-E","Command-Shift-E"),exec:function(e){e.commands.replay(e)},readOnly:!0},{name:"jumptomatching",description:"Jump to matching",bindKey:o("Ctrl-\\|Ctrl-P","Command-\\"),exec:function(e){e.jumpToMatching()},multiSelectAction:"forEach",scrollIntoView:"animate",readOnly:!0},{name:"selecttomatching",description:"Select to matching",bindKey:o("Ctrl-Shift-\\|Ctrl-Shift-P","Command-Shift-\\"),exec:function(e){e.jumpToMatching(!0)},multiSelectAction:"forEach",scrollIntoView:"animate",readOnly:!0},{name:"expandToMatching",description:"Expand to matching",bindKey:o("Ctrl-Shift-M","Ctrl-Shift-M"),exec:function(e){e.jumpToMatching(!0,!0)},multiSelectAction:"forEach",scrollIntoView:"animate",readOnly:!0},{name:"passKeysToBrowser",description:"Pass keys to browser",bindKey:o(null,null),exec:function(){},passEvent:!0,readOnly:!0},{name:"copy",description:"Copy",exec:function(e){},readOnly:!0},{name:"cut",description:"Cut",exec:function(e){var t=e.$copyWithEmptySelection&&e.selection.isEmpty(),n=t?e.selection.getLineRange():e.selection.getRange();e._emit("cut",n),n.isEmpty()||e.session.remove(n),e.clearSelection()},scrollIntoView:"cursor",multiSelectAction:"forEach"},{name:"paste",description:"Paste",exec:function(e,t){e.$handlePaste(t)},scrollIntoView:"cursor"},{name:"removeline",description:"Remove line",bindKey:o("Ctrl-D","Command-D"),exec:function(e){e.removeLines()},scrollIntoView:"cursor",multiSelectAction:"forEachLine"},{name:"duplicateSelection",description:"Duplicate selection",bindKey:o("Ctrl-Shift-D","Command-Shift-D"),exec:function(e){e.duplicateSelection()},scrollIntoView:"cursor",multiSelectAction:"forEach"},{name:"sortlines",description:"Sort lines",bindKey:o("Ctrl-Alt-S","Command-Alt-S"),exec:function(e){e.sortLines()},scrollIntoView:"selection",multiSelectAction:"forEachLine"},{name:"togglecomment",description:"Toggle comment",bindKey:o("Ctrl-/","Command-/"),exec:function(e){e.toggleCommentLines()},multiSelectAction:"forEachLine",scrollIntoView:"selectionPart"},{name:"toggleBlockComment",description:"Toggle block comment",bindKey:o("Ctrl-Shift-/","Command-Shift-/"),exec:function(e){e.toggleBlockComment()},multiSelectAction:"forEach",scrollIntoView:"selectionPart"},{name:"modifyNumberUp",description:"Modify number up",bindKey:o("Ctrl-Shift-Up","Alt-Shift-Up"),exec:function(e){e.modifyNumber(1)},scrollIntoView:"cursor",multiSelectAction:"forEach"},{name:"modifyNumberDown",description:"Modify number down",bindKey:o("Ctrl-Shift-Down","Alt-Shift-Down"),exec:function(e){e.modifyNumber(-1)},scrollIntoView:"cursor",multiSelectAction:"forEach"},{name:"replace",description:"Replace",bindKey:o("Ctrl-H","Command-Option-F"),exec:function(e){i.loadModule("ace/ext/searchbox",function(t){t.Search(e,!0)})}},{name:"undo",description:"Undo",bindKey:o("Ctrl-Z","Command-Z"),exec:function(e){e.undo()}},{name:"redo",description:"Redo",bindKey:o("Ctrl-Shift-Z|Ctrl-Y","Command-Shift-Z|Command-Y"),exec:function(e){e.redo()}},{name:"copylinesup",description:"Copy lines up",bindKey:o("Alt-Shift-Up","Command-Option-Up"),exec:function(e){e.copyLinesUp()},scrollIntoView:"cursor"},{name:"movelinesup",description:"Move lines up",bindKey:o("Alt-Up","Option-Up"),exec:function(e){e.moveLinesUp()},scrollIntoView:"cursor"},{name:"copylinesdown",description:"Copy lines down",bindKey:o("Alt-Shift-Down","Command-Option-Down"),exec:function(e){e.copyLinesDown()},scrollIntoView:"cursor"},{name:"movelinesdown",description:"Move lines down",bindKey:o("Alt-Down","Option-Down"),exec:function(e){e.moveLinesDown()},scrollIntoView:"cursor"},{name:"del",description:"Delete",bindKey:o("Delete","Delete|Ctrl-D|Shift-Delete"),exec:function(e){e.remove("right")},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"backspace",description:"Backspace",bindKey:o("Shift-Backspace|Backspace","Ctrl-Backspace|Shift-Backspace|Backspace|Ctrl-H"),exec:function(e){e.remove("left")},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"cut_or_delete",description:"Cut or delete",bindKey:o("Shift-Delete",null),exec:function(e){if(!e.selection.isEmpty())return!1;e.remove("left")},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"removetolinestart",description:"Remove to line start",bindKey:o("Alt-Backspace","Command-Backspace"),exec:function(e){e.removeToLineStart()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"removetolineend",description:"Remove to line end",bindKey:o("Alt-Delete","Ctrl-K|Command-Delete"),exec:function(e){e.removeToLineEnd()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"removetolinestarthard",description:"Remove to line start hard",bindKey:o("Ctrl-Shift-Backspace",null),exec:function(e){var t=e.selection.getRange();t.start.column=0,e.session.remove(t)},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"removetolineendhard",description:"Remove to line end hard",bindKey:o("Ctrl-Shift-Delete",null),exec:function(e){var t=e.selection.getRange();t.end.column=Number.MAX_VALUE,e.session.remove(t)},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"removewordleft",description:"Remove word left",bindKey:o("Ctrl-Backspace","Alt-Backspace|Ctrl-Alt-Backspace"),exec:function(e){e.removeWordLeft()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"removewordright",description:"Remove word right",bindKey:o("Ctrl-Delete","Alt-Delete"),exec:function(e){e.removeWordRight()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"outdent",description:"Outdent",bindKey:o("Shift-Tab","Shift-Tab"),exec:function(e){e.blockOutdent()},multiSelectAction:"forEach",scrollIntoView:"selectionPart"},{name:"indent",description:"Indent",bindKey:o("Tab","Tab"),exec:function(e){e.indent()},multiSelectAction:"forEach",scrollIntoView:"selectionPart"},{name:"blockoutdent",description:"Block outdent",bindKey:o("Ctrl-[","Ctrl-["),exec:function(e){e.blockOutdent()},multiSelectAction:"forEachLine",scrollIntoView:"selectionPart"},{name:"blockindent",description:"Block indent",bindKey:o("Ctrl-]","Ctrl-]"),exec:function(e){e.blockIndent()},multiSelectAction:"forEachLine",scrollIntoView:"selectionPart"},{name:"insertstring",description:"Insert string",exec:function(e,t){e.insert(t)},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"inserttext",description:"Insert text",exec:function(e,t){e.insert(r.stringRepeat(t.text||"",t.times||1))},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"splitline",description:"Split line",bindKey:o(null,"Ctrl-O"),exec:function(e){e.splitLine()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"transposeletters",description:"Transpose letters",bindKey:o("Alt-Shift-X","Ctrl-T"),exec:function(e){e.transposeLetters()},multiSelectAction:function(e){e.transposeSelections(1)},scrollIntoView:"cursor"},{name:"touppercase",description:"To uppercase",bindKey:o("Ctrl-U","Ctrl-U"),exec:function(e){e.toUpperCase()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"tolowercase",description:"To lowercase",bindKey:o("Ctrl-Shift-U","Ctrl-Shift-U"),exec:function(e){e.toLowerCase()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"autoindent",description:"Auto Indent",bindKey:o(null,null),exec:function(e){e.autoIndent()},multiSelectAction:"forEachLine",scrollIntoView:"animate"},{name:"expandtoline",description:"Expand to line",bindKey:o("Ctrl-Shift-L","Command-Shift-L"),exec:function(e){var t=e.selection.getRange();t.start.column=t.end.column=0,t.end.row++,e.selection.setRange(t,!1)},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"joinlines",description:"Join lines",bindKey:o(null,null),exec:function(e){var t=e.selection.isBackwards(),n=t?e.selection.getSelectionLead():e.selection.getSelectionAnchor(),i=t?e.selection.getSelectionAnchor():e.selection.getSelectionLead(),o=e.session.doc.getLine(n.row).length,u=e.session.doc.getTextRange(e.selection.getRange()),a=u.replace(/\n\s*/," ").length,f=e.session.doc.getLine(n.row);for(var l=n.row+1;l<=i.row+1;l++){var c=r.stringTrimLeft(r.stringTrimRight(e.session.doc.getLine(l)));c.length!==0&&(c=" "+c),f+=c}i.row+10?(e.selection.moveCursorTo(n.row,n.column),e.selection.selectTo(n.row,n.column+a)):(o=e.session.doc.getLine(n.row).length>o?o+1:o,e.selection.moveCursorTo(n.row,o))},multiSelectAction:"forEach",readOnly:!0},{name:"invertSelection",description:"Invert selection",bindKey:o(null,null),exec:function(e){var t=e.session.doc.getLength()-1,n=e.session.doc.getLine(t).length,r=e.selection.rangeList.ranges,i=[];r.length<1&&(r=[e.selection.getRange()]);for(var o=0;o=i.lastRow||r.end.row<=i.firstRow)&&this.renderer.scrollSelectionIntoView(this.selection.anchor,this.selection.lead);break;default:}n=="animate"&&this.renderer.animateScrolling(this.curOp.scrollTop)}var s=this.selection.toJSON();this.curOp.selectionAfter=s,this.$lastSel=this.selection.toJSON(),this.session.getUndoManager().addSelection(s),this.prevOp=this.curOp,this.curOp=null}},this.$mergeableCommands=["backspace","del","insertstring"],this.$historyTracker=function(e){if(!this.$mergeUndoDeltas)return;var t=this.prevOp,n=this.$mergeableCommands,r=t.command&&e.command.name==t.command.name;if(e.command.name=="insertstring"){var i=e.args;this.mergeNextCommand===undefined&&(this.mergeNextCommand=!0),r=r&&this.mergeNextCommand&&(!/\s/.test(i)||/\s/.test(t.args)),this.mergeNextCommand=!0}else r=r&&n.indexOf(e.command.name)!==-1;this.$mergeUndoDeltas!="always"&&Date.now()-this.sequenceStartTime>2e3&&(r=!1),r?this.session.mergeUndoDeltas=!0:n.indexOf(e.command.name)!==-1&&(this.sequenceStartTime=Date.now())},this.setKeyboardHandler=function(e,t){if(e&&typeof e=="string"&&e!="ace"){this.$keybindingId=e;var n=this;g.loadModule(["keybinding",e],function(r){n.$keybindingId==e&&n.keyBinding.setKeyboardHandler(r&&r.handler),t&&t()})}else this.$keybindingId=null,this.keyBinding.setKeyboardHandler(e),t&&t()},this.getKeyboardHandler=function(){return this.keyBinding.getKeyboardHandler()},this.setSession=function(e){if(this.session==e)return;this.curOp&&this.endOperation(),this.curOp={};var t=this.session;if(t){this.session.off("change",this.$onDocumentChange),this.session.off("changeMode",this.$onChangeMode),this.session.off("tokenizerUpdate",this.$onTokenizerUpdate),this.session.off("changeTabSize",this.$onChangeTabSize),this.session.off("changeWrapLimit",this.$onChangeWrapLimit),this.session.off("changeWrapMode",this.$onChangeWrapMode),this.session.off("changeFold",this.$onChangeFold),this.session.off("changeFrontMarker",this.$onChangeFrontMarker),this.session.off("changeBackMarker",this.$onChangeBackMarker),this.session.off("changeBreakpoint",this.$onChangeBreakpoint),this.session.off("changeAnnotation",this.$onChangeAnnotation),this.session.off("changeOverwrite",this.$onCursorChange),this.session.off("changeScrollTop",this.$onScrollTopChange),this.session.off("changeScrollLeft",this.$onScrollLeftChange);var n=this.session.getSelection();n.off("changeCursor",this.$onCursorChange),n.off("changeSelection",this.$onSelectionChange)}this.session=e,e?(this.$onDocumentChange=this.onDocumentChange.bind(this),e.on("change",this.$onDocumentChange),this.renderer.setSession(e),this.$onChangeMode=this.onChangeMode.bind(this),e.on("changeMode",this.$onChangeMode),this.$onTokenizerUpdate=this.onTokenizerUpdate.bind(this),e.on("tokenizerUpdate",this.$onTokenizerUpdate),this.$onChangeTabSize=this.renderer.onChangeTabSize.bind(this.renderer),e.on("changeTabSize",this.$onChangeTabSize),this.$onChangeWrapLimit=this.onChangeWrapLimit.bind(this),e.on("changeWrapLimit",this.$onChangeWrapLimit),this.$onChangeWrapMode=this.onChangeWrapMode.bind(this),e.on("changeWrapMode",this.$onChangeWrapMode),this.$onChangeFold=this.onChangeFold.bind(this),e.on("changeFold",this.$onChangeFold),this.$onChangeFrontMarker=this.onChangeFrontMarker.bind(this),this.session.on("changeFrontMarker",this.$onChangeFrontMarker),this.$onChangeBackMarker=this.onChangeBackMarker.bind(this),this.session.on("changeBackMarker",this.$onChangeBackMarker),this.$onChangeBreakpoint=this.onChangeBreakpoint.bind(this),this.session.on("changeBreakpoint",this.$onChangeBreakpoint),this.$onChangeAnnotation=this.onChangeAnnotation.bind(this),this.session.on("changeAnnotation",this.$onChangeAnnotation),this.$onCursorChange=this.onCursorChange.bind(this),this.session.on("changeOverwrite",this.$onCursorChange),this.$onScrollTopChange=this.onScrollTopChange.bind(this),this.session.on("changeScrollTop",this.$onScrollTopChange),this.$onScrollLeftChange=this.onScrollLeftChange.bind(this),this.session.on("changeScrollLeft",this.$onScrollLeftChange),this.selection=e.getSelection(),this.selection.on("changeCursor",this.$onCursorChange),this.$onSelectionChange=this.onSelectionChange.bind(this),this.selection.on("changeSelection",this.$onSelectionChange),this.onChangeMode(),this.onCursorChange(),this.onScrollTopChange(),this.onScrollLeftChange(),this.onSelectionChange(),this.onChangeFrontMarker(),this.onChangeBackMarker(),this.onChangeBreakpoint(),this.onChangeAnnotation(),this.session.getUseWrapMode()&&this.renderer.adjustWrapLimit(),this.renderer.updateFull()):(this.selection=null,this.renderer.setSession(e)),this._signal("changeSession",{session:e,oldSession:t}),this.curOp=null,t&&t._signal("changeEditor",{oldEditor:this}),e&&e._signal("changeEditor",{editor:this}),e&&e.bgTokenizer&&e.bgTokenizer.scheduleStart()},this.getSession=function(){return this.session},this.setValue=function(e,t){return this.session.doc.setValue(e),t?t==1?this.navigateFileEnd():t==-1&&this.navigateFileStart():this.selectAll(),e},this.getValue=function(){return this.session.getValue()},this.getSelection=function(){return this.selection},this.resize=function(e){this.renderer.onResize(e)},this.setTheme=function(e,t){this.renderer.setTheme(e,t)},this.getTheme=function(){return this.renderer.getTheme()},this.setStyle=function(e){this.renderer.setStyle(e)},this.unsetStyle=function(e){this.renderer.unsetStyle(e)},this.getFontSize=function(){return this.getOption("fontSize")||i.computedStyle(this.container).fontSize},this.setFontSize=function(e){this.setOption("fontSize",e)},this.$highlightBrackets=function(){if(this.$highlightPending)return;var e=this;this.$highlightPending=!0,setTimeout(function(){e.$highlightPending=!1;var t=e.session;if(!t||!t.bgTokenizer)return;t.$bracketHighlight&&(t.$bracketHighlight.markerIds.forEach(function(e){t.removeMarker(e)}),t.$bracketHighlight=null);var n=t.getMatchingBracketRanges(e.getCursorPosition());!n&&t.$mode.getMatching&&(n=t.$mode.getMatching(e.session));if(!n)return;var r="ace_bracket";Array.isArray(n)?n.length==1&&(r="ace_error_bracket"):n=[n],n.length==2&&(p.comparePoints(n[0].end,n[1].start)==0?n=[p.fromPoints(n[0].start,n[1].end)]:p.comparePoints(n[0].start,n[1].end)==0&&(n=[p.fromPoints(n[1].start,n[0].end)])),t.$bracketHighlight={ranges:n,markerIds:n.map(function(e){return t.addMarker(e,r,"text")})}},50)},this.$highlightTags=function(){if(this.$highlightTagPending)return;var e=this;this.$highlightTagPending=!0,setTimeout(function(){e.$highlightTagPending=!1;var t=e.session;if(!t||!t.bgTokenizer)return;var n=e.getCursorPosition(),r=new y(e.session,n.row,n.column),i=r.getCurrentToken();if(!i||!/\b(?:tag-open|tag-name)/.test(i.type)){t.removeMarker(t.$tagHighlight),t.$tagHighlight=null;return}if(i.type.indexOf("tag-open")!==-1){i=r.stepForward();if(!i)return}var s=i.value,o=i.value,u=0,a=r.stepBackward();if(a.value==="<"){do a=i,i=r.stepForward(),i&&(i.type.indexOf("tag-name")!==-1?(o=i.value,s===o&&(a.value==="<"?u++:a.value===""&&u--);while(i&&u>=0)}else{do{i=a,a=r.stepBackward();if(i)if(i.type.indexOf("tag-name")!==-1)s===i.value&&(a.value==="<"?u++:a.value===""){var f=0,l=a;while(l){if(l.type.indexOf("tag-name")!==-1&&l.value===s){u--;break}if(l.value==="<")break;l=r.stepBackward(),f++}for(var c=0;c1)&&(t=!1)}if(e.$highlightLineMarker&&!t)e.removeMarker(e.$highlightLineMarker.id),e.$highlightLineMarker=null;else if(!e.$highlightLineMarker&&t){var n=new p(t.row,t.column,t.row,Infinity);n.id=e.addMarker(n,"ace_active-line","screenLine"),e.$highlightLineMarker=n}else t&&(e.$highlightLineMarker.start.row=t.row,e.$highlightLineMarker.end.row=t.row,e.$highlightLineMarker.start.column=t.column,e._signal("changeBackMarker"))},this.onSelectionChange=function(e){var t=this.session;t.$selectionMarker&&t.removeMarker(t.$selectionMarker),t.$selectionMarker=null;if(!this.selection.isEmpty()){var n=this.selection.getRange(),r=this.getSelectionStyle();t.$selectionMarker=t.addMarker(n,"ace_selection",r)}else this.$updateHighlightActiveLine();var i=this.$highlightSelectedWord&&this.$getSelectionHighLightRegexp();this.session.highlight(i),this._signal("changeSelection")},this.$getSelectionHighLightRegexp=function(){var e=this.session,t=this.getSelectionRange();if(t.isEmpty()||t.isMultiLine())return;var n=t.start.column,r=t.end.column,i=e.getLine(t.start.row),s=i.substring(n,r);if(s.length>5e3||!/[\w\d]/.test(s))return;var o=this.$search.$assembleRegExp({wholeWord:!0,caseSensitive:!0,needle:s}),u=i.substring(n-1,r+1);if(!o.test(u))return;return o},this.onChangeFrontMarker=function(){this.renderer.updateFrontMarkers()},this.onChangeBackMarker=function(){this.renderer.updateBackMarkers()},this.onChangeBreakpoint=function(){this.renderer.updateBreakpoints()},this.onChangeAnnotation=function(){this.renderer.setAnnotations(this.session.getAnnotations())},this.onChangeMode=function(e){this.renderer.updateText(),this._emit("changeMode",e)},this.onChangeWrapLimit=function(){this.renderer.updateFull()},this.onChangeWrapMode=function(){this.renderer.onResize(!0)},this.onChangeFold=function(){this.$updateHighlightActiveLine(),this.renderer.updateFull()},this.getSelectedText=function(){return this.session.getTextRange(this.getSelectionRange())},this.getCopyText=function(){var e=this.getSelectedText(),t=this.session.doc.getNewLineCharacter(),n=!1;if(!e&&this.$copyWithEmptySelection){n=!0;var r=this.selection.getAllRanges();for(var i=0;iu.search(/\S|$/)){var a=u.substr(i.column).search(/\S|$/);n.doc.removeInLine(i.row,i.column,i.column+a)}}this.clearSelection();var f=i.column,l=n.getState(i.row),u=n.getLine(i.row),c=r.checkOutdent(l,u,e);n.insert(i,e),s&&s.selection&&(s.selection.length==2?this.selection.setSelectionRange(new p(i.row,f+s.selection[0],i.row,f+s.selection[1])):this.selection.setSelectionRange(new p(i.row+s.selection[0],s.selection[1],i.row+s.selection[2],s.selection[3])));if(this.$enableAutoIndent){if(n.getDocument().isNewLine(e)){var h=r.getNextLineIndent(l,u.slice(0,i.column),n.getTabString());n.insert({row:i.row+1,column:0},h)}c&&r.autoOutdent(l,n,i.row)}},this.autoIndent=function(){var e=this.session,t=e.getMode(),n,r;if(this.selection.isEmpty())n=0,r=e.doc.getLength()-1;else{var i=this.getSelectionRange();n=i.start.row,r=i.end.row}var s="",o="",u="",a,f,l,c=e.getTabString();for(var h=n;h<=r;h++)h>0&&(s=e.getState(h-1),o=e.getLine(h-1),u=t.getNextLineIndent(s,o,c)),a=e.getLine(h),f=t.$getIndent(a),u!==f&&(f.length>0&&(l=new p(h,0,h,f.length),e.remove(l)),u.length>0&&e.insert({row:h,column:0},u)),t.autoOutdent(s,e,h)},this.onTextInput=function(e,t){if(!t)return this.keyBinding.onTextInput(e);this.startOperation({command:{name:"insertstring"}});var n=this.applyComposition.bind(this,e,t);this.selection.rangeCount?this.forEachSelection(n):n(),this.endOperation()},this.applyComposition=function(e,t){if(t.extendLeft||t.extendRight){var n=this.selection.getRange();n.start.column-=t.extendLeft,n.end.column+=t.extendRight,n.start.column<0&&(n.start.row--,n.start.column+=this.session.getLine(n.start.row).length+1),this.selection.setRange(n),!e&&!n.isEmpty()&&this.remove()}(e||!this.selection.isEmpty())&&this.insert(e,!0);if(t.restoreStart||t.restoreEnd){var n=this.selection.getRange();n.start.column-=t.restoreStart,n.end.column-=t.restoreEnd,this.selection.setRange(n)}},this.onCommandKey=function(e,t,n){return this.keyBinding.onCommandKey(e,t,n)},this.setOverwrite=function(e){this.session.setOverwrite(e)},this.getOverwrite=function(){return this.session.getOverwrite()},this.toggleOverwrite=function(){this.session.toggleOverwrite()},this.setScrollSpeed=function(e){this.setOption("scrollSpeed",e)},this.getScrollSpeed=function(){return this.getOption("scrollSpeed")},this.setDragDelay=function(e){this.setOption("dragDelay",e)},this.getDragDelay=function(){return this.getOption("dragDelay")},this.setSelectionStyle=function(e){this.setOption("selectionStyle",e)},this.getSelectionStyle=function(){return this.getOption("selectionStyle")},this.setHighlightActiveLine=function(e){this.setOption("highlightActiveLine",e)},this.getHighlightActiveLine=function(){return this.getOption("highlightActiveLine")},this.setHighlightGutterLine=function(e){this.setOption("highlightGutterLine",e)},this.getHighlightGutterLine=function(){return this.getOption("highlightGutterLine")},this.setHighlightSelectedWord=function(e){this.setOption("highlightSelectedWord",e)},this.getHighlightSelectedWord=function(){return this.$highlightSelectedWord},this.setAnimatedScroll=function(e){this.renderer.setAnimatedScroll(e)},this.getAnimatedScroll=function(){return this.renderer.getAnimatedScroll()},this.setShowInvisibles=function(e){this.renderer.setShowInvisibles(e)},this.getShowInvisibles=function(){return this.renderer.getShowInvisibles()},this.setDisplayIndentGuides=function(e){this.renderer.setDisplayIndentGuides(e)},this.getDisplayIndentGuides=function(){return this.renderer.getDisplayIndentGuides()},this.setShowPrintMargin=function(e){this.renderer.setShowPrintMargin(e)},this.getShowPrintMargin=function(){return this.renderer.getShowPrintMargin()},this.setPrintMarginColumn=function(e){this.renderer.setPrintMarginColumn(e)},this.getPrintMarginColumn=function(){return this.renderer.getPrintMarginColumn()},this.setReadOnly=function(e){this.setOption("readOnly",e)},this.getReadOnly=function(){return this.getOption("readOnly")},this.setBehavioursEnabled=function(e){this.setOption("behavioursEnabled",e)},this.getBehavioursEnabled=function(){return this.getOption("behavioursEnabled")},this.setWrapBehavioursEnabled=function(e){this.setOption("wrapBehavioursEnabled",e)},this.getWrapBehavioursEnabled=function(){return this.getOption("wrapBehavioursEnabled")},this.setShowFoldWidgets=function(e){this.setOption("showFoldWidgets",e)},this.getShowFoldWidgets=function(){return this.getOption("showFoldWidgets")},this.setFadeFoldWidgets=function(e){this.setOption("fadeFoldWidgets",e)},this.getFadeFoldWidgets=function(){return this.getOption("fadeFoldWidgets")},this.remove=function(e){this.selection.isEmpty()&&(e=="left"?this.selection.selectLeft():this.selection.selectRight());var t=this.getSelectionRange();if(this.getBehavioursEnabled()){var n=this.session,r=n.getState(t.start.row),i=n.getMode().transformAction(r,"deletion",this,n,t);if(t.end.column===0){var s=n.getTextRange(t);if(s[s.length-1]=="\n"){var o=n.getLine(t.end.row);/^\s+$/.test(o)&&(t.end.column=o.length)}}i&&(t=i)}this.session.remove(t),this.clearSelection()},this.removeWordRight=function(){this.selection.isEmpty()&&this.selection.selectWordRight(),this.session.remove(this.getSelectionRange()),this.clearSelection()},this.removeWordLeft=function(){this.selection.isEmpty()&&this.selection.selectWordLeft(),this.session.remove(this.getSelectionRange()),this.clearSelection()},this.removeToLineStart=function(){this.selection.isEmpty()&&this.selection.selectLineStart(),this.selection.isEmpty()&&this.selection.selectLeft(),this.session.remove(this.getSelectionRange()),this.clearSelection()},this.removeToLineEnd=function(){this.selection.isEmpty()&&this.selection.selectLineEnd();var e=this.getSelectionRange();e.start.column==e.end.column&&e.start.row==e.end.row&&(e.end.column=0,e.end.row++),this.session.remove(e),this.clearSelection()},this.splitLine=function(){this.selection.isEmpty()||(this.session.remove(this.getSelectionRange()),this.clearSelection());var e=this.getCursorPosition();this.insert("\n"),this.moveCursorToPosition(e)},this.transposeLetters=function(){if(!this.selection.isEmpty())return;var e=this.getCursorPosition(),t=e.column;if(t===0)return;var n=this.session.getLine(e.row),r,i;tt.toLowerCase()?1:0});var i=new p(0,0,0,0);for(var r=e.first;r<=e.last;r++){var s=t.getLine(r);i.start.row=r,i.end.row=r,i.end.column=s.length,t.replace(i,n[r-e.first])}},this.toggleCommentLines=function(){var e=this.session.getState(this.getCursorPosition().row),t=this.$getSelectedRows();this.session.getMode().toggleCommentLines(e,this.session,t.first,t.last)},this.toggleBlockComment=function(){var e=this.getCursorPosition(),t=this.session.getState(e.row),n=this.getSelectionRange();this.session.getMode().toggleBlockComment(t,this.session,n,e)},this.getNumberAt=function(e,t){var n=/[\-]?[0-9]+(?:\.[0-9]+)?/g;n.lastIndex=0;var r=this.session.getLine(e);while(n.lastIndex=t){var s={value:i[0],start:i.index,end:i.index+i[0].length};return s}}return null},this.modifyNumber=function(e){var t=this.selection.getCursor().row,n=this.selection.getCursor().column,r=new p(t,n-1,t,n),i=this.session.getTextRange(r);if(!isNaN(parseFloat(i))&&isFinite(i)){var s=this.getNumberAt(t,n);if(s){var o=s.value.indexOf(".")>=0?s.start+s.value.indexOf(".")+1:s.end,u=s.start+s.value.length-o,a=parseFloat(s.value);a*=Math.pow(10,u),o!==s.end&&n=u&&o<=a&&(n=t,f.selection.clearSelection(),f.moveCursorTo(e,u+r),f.selection.selectTo(e,a+r)),u=a});var l=this.$toggleWordPairs,c;for(var h=0;hp+1)break;p=d.last}l--,u=this.session.$moveLines(h,p,t?0:e),t&&e==-1&&(c=l+1);while(c<=l)o[c].moveBy(u,0),c++;t||(u=0),a+=u}i.fromOrientedRange(i.ranges[0]),i.rangeList.attach(this.session),this.inVirtualSelectionMode=!1}},this.$getSelectedRows=function(e){return e=(e||this.getSelectionRange()).collapseRows(),{first:this.session.getRowFoldStart(e.start.row),last:this.session.getRowFoldEnd(e.end.row)}},this.onCompositionStart=function(e){this.renderer.showComposition(e)},this.onCompositionUpdate=function(e){this.renderer.setCompositionText(e)},this.onCompositionEnd=function(){this.renderer.hideComposition()},this.getFirstVisibleRow=function(){return this.renderer.getFirstVisibleRow()},this.getLastVisibleRow=function(){return this.renderer.getLastVisibleRow()},this.isRowVisible=function(e){return e>=this.getFirstVisibleRow()&&e<=this.getLastVisibleRow()},this.isRowFullyVisible=function(e){return e>=this.renderer.getFirstFullyVisibleRow()&&e<=this.renderer.getLastFullyVisibleRow()},this.$getVisibleRowCount=function(){return this.renderer.getScrollBottomRow()-this.renderer.getScrollTopRow()+1},this.$moveByPage=function(e,t){var n=this.renderer,r=this.renderer.layerConfig,i=e*Math.floor(r.height/r.lineHeight);t===!0?this.selection.$moveSelection(function(){this.moveCursorBy(i,0)}):t===!1&&(this.selection.moveCursorBy(i,0),this.selection.clearSelection());var s=n.scrollTop;n.scrollBy(0,i*r.lineHeight),t!=null&&n.scrollCursorIntoView(null,.5),n.animateScrolling(s)},this.selectPageDown=function(){this.$moveByPage(1,!0)},this.selectPageUp=function(){this.$moveByPage(-1,!0)},this.gotoPageDown=function(){this.$moveByPage(1,!1)},this.gotoPageUp=function(){this.$moveByPage(-1,!1)},this.scrollPageDown=function(){this.$moveByPage(1)},this.scrollPageUp=function(){this.$moveByPage(-1)},this.scrollToRow=function(e){this.renderer.scrollToRow(e)},this.scrollToLine=function(e,t,n,r){this.renderer.scrollToLine(e,t,n,r)},this.centerSelection=function(){var e=this.getSelectionRange(),t={row:Math.floor(e.start.row+(e.end.row-e.start.row)/2),column:Math.floor(e.start.column+(e.end.column-e.start.column)/2)};this.renderer.alignCursor(t,.5)},this.getCursorPosition=function(){return this.selection.getCursor()},this.getCursorPositionScreen=function(){return this.session.documentToScreenPosition(this.getCursorPosition())},this.getSelectionRange=function(){return this.selection.getRange()},this.selectAll=function(){this.selection.selectAll()},this.clearSelection=function(){this.selection.clearSelection()},this.moveCursorTo=function(e,t){this.selection.moveCursorTo(e,t)},this.moveCursorToPosition=function(e){this.selection.moveCursorToPosition(e)},this.jumpToMatching=function(e,t){var n=this.getCursorPosition(),r=new y(this.session,n.row,n.column),i=r.getCurrentToken(),s=i||r.stepForward();if(!s)return;var o,u=!1,a={},f=n.column-s.start,l,c={")":"(","(":"(","]":"[","[":"[","{":"{","}":"{"};do{if(s.value.match(/[{}()\[\]]/g))for(;f=0;--s)this.$tryReplace(n[s],e)&&r++;return this.selection.setSelectionRange(i),r},this.$tryReplace=function(e,t){var n=this.session.getTextRange(e);return t=this.$search.replace(n,t),t!==null?(e.end=this.session.replace(e,t),e):null},this.getLastSearchOptions=function(){return this.$search.getOptions()},this.find=function(e,t,n){t||(t={}),typeof e=="string"||e instanceof RegExp?t.needle=e:typeof e=="object"&&r.mixin(t,e);var i=this.selection.getRange();t.needle==null&&(e=this.session.getTextRange(i)||this.$search.$options.needle,e||(i=this.session.getWordRange(i.start.row,i.start.column),e=this.session.getTextRange(i)),this.$search.set({needle:e})),this.$search.set(t),t.start||this.$search.set({start:i});var s=this.$search.find(this.session);if(t.preventScroll)return s;if(s)return this.revealRange(s,n),s;t.backwards?i.start=i.end:i.end=i.start,this.selection.setRange(i)},this.findNext=function(e,t){this.find({skipCurrent:!0,backwards:!1},e,t)},this.findPrevious=function(e,t){this.find(e,{skipCurrent:!0,backwards:!0},t)},this.revealRange=function(e,t){this.session.unfold(e),this.selection.setSelectionRange(e);var n=this.renderer.scrollTop;this.renderer.scrollSelectionIntoView(e.start,e.end,.5),t!==!1&&this.renderer.animateScrolling(n)},this.undo=function(){this.session.getUndoManager().undo(this.session),this.renderer.scrollCursorIntoView(null,.5)},this.redo=function(){this.session.getUndoManager().redo(this.session),this.renderer.scrollCursorIntoView(null,.5)},this.destroy=function(){this.$toDestroy&&(this.$toDestroy.forEach(function(e){e.destroy()}),this.$toDestroy=null),this.$mouseHandler&&this.$mouseHandler.destroy(),this.renderer.destroy(),this._signal("destroy",this),this.session&&this.session.destroy(),this._$emitInputEvent&&this._$emitInputEvent.cancel(),this.removeAllListeners()},this.setAutoScrollEditorIntoView=function(e){if(!e)return;var t,n=this,r=!1;this.$scrollAnchor||(this.$scrollAnchor=document.createElement("div"));var i=this.$scrollAnchor;i.style.cssText="position:absolute",this.container.insertBefore(i,this.container.firstChild);var s=this.on("changeSelection",function(){r=!0}),o=this.renderer.on("beforeRender",function(){r&&(t=n.renderer.container.getBoundingClientRect())}),u=this.renderer.on("afterRender",function(){if(r&&t&&(n.isFocused()||n.searchBox&&n.searchBox.isFocused())){var e=n.renderer,s=e.$cursorLayer.$pixelPos,o=e.layerConfig,u=s.top-o.offset;s.top>=0&&u+t.top<0?r=!0:s.topwindow.innerHeight?r=!1:r=null,r!=null&&(i.style.top=u+"px",i.style.left=s.left+"px",i.style.height=o.lineHeight+"px",i.scrollIntoView(r)),r=t=null}});this.setAutoScrollEditorIntoView=function(e){if(e)return;delete this.setAutoScrollEditorIntoView,this.off("changeSelection",s),this.renderer.off("afterRender",u),this.renderer.off("beforeRender",o)}},this.$resetCursorStyle=function(){var e=this.$cursorStyle||"ace",t=this.renderer.$cursorLayer;if(!t)return;t.setSmoothBlinking(/smooth/.test(e)),t.isBlinking=!this.$readOnly&&e!="wide",i.setCssClass(t.element,"ace_slim-cursors",/slim/.test(e))},this.prompt=function(e,t,n){var r=this;g.loadModule("./ext/prompt",function(i){i.prompt(r,e,t,n)})}}.call(w.prototype),g.defineOptions(w.prototype,"editor",{selectionStyle:{set:function(e){this.onSelectionChange(),this._signal("changeSelectionStyle",{data:e})},initialValue:"line"},highlightActiveLine:{set:function(){this.$updateHighlightActiveLine()},initialValue:!0},highlightSelectedWord:{set:function(e){this.$onSelectionChange()},initialValue:!0},readOnly:{set:function(e){this.textInput.setReadOnly(e),this.$resetCursorStyle()},initialValue:!1},copyWithEmptySelection:{set:function(e){this.textInput.setCopyWithEmptySelection(e)},initialValue:!1},cursorStyle:{set:function(e){this.$resetCursorStyle()},values:["ace","slim","smooth","wide"],initialValue:"ace"},mergeUndoDeltas:{values:[!1,!0,"always"],initialValue:!0},behavioursEnabled:{initialValue:!0},wrapBehavioursEnabled:{initialValue:!0},enableAutoIndent:{initialValue:!0},autoScrollEditorIntoView:{set:function(e){this.setAutoScrollEditorIntoView(e)}},keyboardHandler:{set:function(e){this.setKeyboardHandler(e)},get:function(){return this.$keybindingId},handlesSet:!0},value:{set:function(e){this.session.setValue(e)},get:function(){return this.getValue()},handlesSet:!0,hidden:!0},session:{set:function(e){this.setSession(e)},get:function(){return this.session},handlesSet:!0,hidden:!0},showLineNumbers:{set:function(e){this.renderer.$gutterLayer.setShowLineNumbers(e),this.renderer.$loop.schedule(this.renderer.CHANGE_GUTTER),e&&this.$relativeLineNumbers?E.attach(this):E.detach(this)},initialValue:!0},relativeLineNumbers:{set:function(e){this.$showLineNumbers&&e?E.attach(this):E.detach(this)}},placeholder:{set:function(e){this.$updatePlaceholder||(this.$updatePlaceholder=function(){var e=this.session&&(this.renderer.$composition||this.getValue());if(e&&this.renderer.placeholderNode)this.renderer.off("afterRender",this.$updatePlaceholder),i.removeCssClass(this.container,"ace_hasPlaceholder"),this.renderer.placeholderNode.remove(),this.renderer.placeholderNode=null;else if(!e&&!this.renderer.placeholderNode){this.renderer.on("afterRender",this.$updatePlaceholder),i.addCssClass(this.container,"ace_hasPlaceholder");var t=i.createElement("div");t.className="ace_placeholder",t.textContent=this.$placeholder||"",this.renderer.placeholderNode=t,this.renderer.content.appendChild(this.renderer.placeholderNode)}else!e&&this.renderer.placeholderNode&&(this.renderer.placeholderNode.textContent=this.$placeholder||"")}.bind(this),this.on("input",this.$updatePlaceholder)),this.$updatePlaceholder()}},hScrollBarAlwaysVisible:"renderer",vScrollBarAlwaysVisible:"renderer",highlightGutterLine:"renderer",animatedScroll:"renderer",showInvisibles:"renderer",showPrintMargin:"renderer",printMarginColumn:"renderer",printMargin:"renderer",fadeFoldWidgets:"renderer",showFoldWidgets:"renderer",displayIndentGuides:"renderer",showGutter:"renderer",fontSize:"renderer",fontFamily:"renderer",maxLines:"renderer",minLines:"renderer",scrollPastEnd:"renderer",fixedWidthGutter:"renderer",theme:"renderer",hasCssTransforms:"renderer",maxPixelHeight:"renderer",useTextareaForIME:"renderer",scrollSpeed:"$mouseHandler",dragDelay:"$mouseHandler",dragEnabled:"$mouseHandler",focusTimeout:"$mouseHandler",tooltipFollowsMouse:"$mouseHandler",firstLineNumber:"session",overwrite:"session",newLineMode:"session",useWorker:"session",useSoftTabs:"session",navigateWithinSoftTabs:"session",tabSize:"session",wrap:"session",indentedSoftWrap:"session",foldStyle:"session",mode:"session"});var E={getText:function(e,t){return(Math.abs(e.selection.lead.row-t)||t+1+(t<9?"\u00b7":""))+""},getWidth:function(e,t,n){return Math.max(t.toString().length,(n.lastRow+1).toString().length,2)*n.characterWidth},update:function(e,t){t.renderer.$loop.schedule(t.renderer.CHANGE_GUTTER)},attach:function(e){e.renderer.$gutterLayer.$renderer=this,e.on("changeSelection",this.update),this.update(null,e)},detach:function(e){e.renderer.$gutterLayer.$renderer==this&&(e.renderer.$gutterLayer.$renderer=null),e.off("changeSelection",this.update),this.update(null,e)}};t.Editor=w}),define("ace/undomanager",["require","exports","module","ace/range"],function(e,t,n){"use strict";function i(e,t){for(var n=t;n--;){var r=e[n];if(r&&!r[0].ignore){while(n0){a.row+=i,a.column+=a.row==r.row?s:0;continue}!t&&l<=0&&(a.row=n.row,a.column=n.column,l===0&&(a.bias=1))}}function f(e){return{row:e.row,column:e.column}}function l(e){return{start:f(e.start),end:f(e.end),action:e.action,lines:e.lines.slice()}}function c(e){e=e||this;if(Array.isArray(e))return e.map(c).join("\n");var t="";e.action?(t=e.action=="insert"?"+":"-",t+="["+e.lines+"]"):e.value&&(Array.isArray(e.value)?t=e.value.map(h).join("\n"):t=h(e.value)),e.start&&(t+=h(e));if(e.id||e.rev)t+=" ("+(e.id||e.rev)+")";return t}function h(e){return e.start.row+":"+e.start.column+"=>"+e.end.row+":"+e.end.column}function p(e,t){var n=e.action=="insert",r=t.action=="insert";if(n&&r)if(o(t.start,e.end)>=0)m(t,e,-1);else{if(!(o(t.start,e.start)<=0))return null;m(e,t,1)}else if(n&&!r)if(o(t.start,e.end)>=0)m(t,e,-1);else{if(!(o(t.end,e.start)<=0))return null;m(e,t,-1)}else if(!n&&r)if(o(t.start,e.start)>=0)m(t,e,1);else{if(!(o(t.start,e.start)<=0))return null;m(e,t,1)}else if(!n&&!r)if(o(t.start,e.start)>=0)m(t,e,1);else{if(!(o(t.end,e.start)<=0))return null;m(e,t,-1)}return[t,e]}function d(e,t){for(var n=e.length;n--;)for(var r=0;r=0?m(e,t,-1):o(e.start,t.start)<=0?m(t,e,1):(m(e,s.fromPoints(t.start,e.start),-1),m(t,e,1));else if(!n&&r)o(t.start,e.end)>=0?m(t,e,-1):o(t.start,e.start)<=0?m(e,t,1):(m(t,s.fromPoints(e.start,t.start),-1),m(e,t,1));else if(!n&&!r)if(o(t.start,e.end)>=0)m(t,e,-1);else{if(!(o(t.end,e.start)<=0)){var i,u;return o(e.start,t.start)<0&&(i=e,e=y(e,t.start)),o(e.end,t.end)>0&&(u=y(e,t.end)),g(t.end,e.start,e.end,-1),u&&!i&&(e.lines=u.lines,e.start=u.start,e.end=u.end,u=e),[t,i,u].filter(Boolean)}m(e,t,-1)}return[t,e]}function m(e,t,n){g(e.start,t.start,t.end,n),g(e.end,t.start,t.end,n)}function g(e,t,n,r){e.row==(r==1?t:n).row&&(e.column+=r*(n.column-t.column)),e.row+=r*(n.row-t.row)}function y(e,t){var n=e.lines,r=e.end;e.end=f(t);var i=e.end.row-e.start.row,s=n.splice(i,n.length),o=i?t.column:t.column-e.start.column;n.push(s[0].substring(0,o)),s[0]=s[0].substr(o);var u={start:f(t),end:r,lines:s,action:e.action};return u}function b(e,t){t=l(t);for(var n=e.length;n--;){var r=e[n];for(var i=0;i0},this.canRedo=function(){return this.$redoStack.length>0},this.bookmark=function(e){e==undefined&&(e=this.$rev),this.mark=e},this.isAtBookmark=function(){return this.$rev===this.mark},this.toJSON=function(){},this.fromJSON=function(){},this.hasUndo=this.canUndo,this.hasRedo=this.canRedo,this.isClean=this.isAtBookmark,this.markClean=this.bookmark,this.$prettyPrint=function(e){return e?c(e):c(this.$undoStack)+"\n---\n"+c(this.$redoStack)}}).call(r.prototype);var s=e("./range").Range,o=s.comparePoints,u=s.comparePoints;t.UndoManager=r}),define("ace/layer/lines",["require","exports","module","ace/lib/dom"],function(e,t,n){"use strict";var r=e("../lib/dom"),i=function(e,t){this.element=e,this.canvasHeight=t||5e5,this.element.style.height=this.canvasHeight*2+"px",this.cells=[],this.cellCache=[],this.$offsetCoefficient=0};(function(){this.moveContainer=function(e){r.translate(this.element,0,-(e.firstRowScreen*e.lineHeight%this.canvasHeight)-e.offset*this.$offsetCoefficient)},this.pageChanged=function(e,t){return Math.floor(e.firstRowScreen*e.lineHeight/this.canvasHeight)!==Math.floor(t.firstRowScreen*t.lineHeight/this.canvasHeight)},this.computeLineTop=function(e,t,n){var r=t.firstRowScreen*t.lineHeight,i=Math.floor(r/this.canvasHeight),s=n.documentToScreenRow(e,0)*t.lineHeight;return s-i*this.canvasHeight},this.computeLineHeight=function(e,t,n){return t.lineHeight*n.getRowLineCount(e)},this.getLength=function(){return this.cells.length},this.get=function(e){return this.cells[e]},this.shift=function(){this.$cacheCell(this.cells.shift())},this.pop=function(){this.$cacheCell(this.cells.pop())},this.push=function(e){if(Array.isArray(e)){this.cells.push.apply(this.cells,e);var t=r.createFragment(this.element);for(var n=0;ns&&(a=i.end.row+1,i=t.getNextFoldLine(a,i),s=i?i.start.row:Infinity);if(a>r){while(this.$lines.getLength()>u+1)this.$lines.pop();break}o=this.$lines.get(++u),o?o.row=a:(o=this.$lines.createCell(a,e,this.session,f),this.$lines.push(o)),this.$renderCell(o,e,i,a),a++}this._signal("afterRender"),this.$updateGutterWidth(e)},this.$updateGutterWidth=function(e){var t=this.session,n=t.gutterRenderer||this.$renderer,r=t.$firstLineNumber,i=this.$lines.last()?this.$lines.last().text:"";if(this.$fixedWidth||t.$useWrapMode)i=t.getLength()+r-1;var s=n?n.getWidth(t,i,e):i.toString().length*e.characterWidth,o=this.$padding||this.$computePadding();s+=o.left+o.right,s!==this.gutterWidth&&!isNaN(s)&&(this.gutterWidth=s,this.element.parentNode.style.width=this.element.style.width=Math.ceil(this.gutterWidth)+"px",this._signal("changeGutterWidth",s))},this.$updateCursorRow=function(){if(!this.$highlightGutterLine)return;var e=this.session.selection.getCursor();if(this.$cursorRow===e.row)return;this.$cursorRow=e.row},this.updateLineHighlight=function(){if(!this.$highlightGutterLine)return;var e=this.session.selection.cursor.row;this.$cursorRow=e;if(this.$cursorCell&&this.$cursorCell.row==e)return;this.$cursorCell&&(this.$cursorCell.element.className=this.$cursorCell.element.className.replace("ace_gutter-active-line ",""));var t=this.$lines.cells;this.$cursorCell=null;for(var n=0;n=this.$cursorRow){if(r.row>this.$cursorRow){var i=this.session.getFoldLine(this.$cursorRow);if(!(n>0&&i&&i.start.row==t[n-1].row))break;r=t[n-1]}r.element.className="ace_gutter-active-line "+r.element.className,this.$cursorCell=r;break}}},this.scrollLines=function(e){var t=this.config;this.config=e,this.$updateCursorRow();if(this.$lines.pageChanged(t,e))return this.update(e);this.$lines.moveContainer(e);var n=Math.min(e.lastRow+e.gutterOffset,this.session.getLength()-1),r=this.oldLastRow;this.oldLastRow=n;if(!t||r0;i--)this.$lines.shift();if(r>n)for(var i=this.session.getFoldedRowCount(n+1,r);i>0;i--)this.$lines.pop();e.firstRowr&&this.$lines.push(this.$renderLines(e,r+1,n)),this.updateLineHighlight(),this._signal("afterRender"),this.$updateGutterWidth(e)},this.$renderLines=function(e,t,n){var r=[],i=t,s=this.session.getNextFoldLine(i),o=s?s.start.row:Infinity;for(;;){i>o&&(i=s.end.row+1,s=this.session.getNextFoldLine(i,s),o=s?s.start.row:Infinity);if(i>n)break;var u=this.$lines.createCell(i,e,this.session,f);this.$renderCell(u,e,s,i),r.push(u),i++}return r},this.$renderCell=function(e,t,n,i){var s=e.element,o=this.session,u=s.childNodes[0],a=s.childNodes[1],f=o.$firstLineNumber,l=o.$breakpoints,c=o.$decorations,h=o.gutterRenderer||this.$renderer,p=this.$showFoldWidgets&&o.foldWidgets,d=n?n.start.row:Number.MAX_VALUE,v="ace_gutter-cell ";this.$highlightGutterLine&&(i==this.$cursorRow||n&&i=d&&this.$cursorRow<=n.end.row)&&(v+="ace_gutter-active-line ",this.$cursorCell!=e&&(this.$cursorCell&&(this.$cursorCell.element.className=this.$cursorCell.element.className.replace("ace_gutter-active-line ","")),this.$cursorCell=e)),l[i]&&(v+=l[i]),c[i]&&(v+=c[i]),this.$annotations[i]&&(v+=this.$annotations[i].className),s.className!=v&&(s.className=v);if(p){var m=p[i];m==null&&(m=p[i]=o.getFoldWidget(i))}if(m){var v="ace_fold-widget ace_"+m;m=="start"&&i==d&&in.right-t.right)return"foldWidgets"}}).call(a.prototype),t.Gutter=a}),define("ace/layer/marker",["require","exports","module","ace/range","ace/lib/dom"],function(e,t,n){"use strict";var r=e("../range").Range,i=e("../lib/dom"),s=function(e){this.element=i.createElement("div"),this.element.className="ace_layer ace_marker-layer",e.appendChild(this.element)};(function(){function e(e,t,n,r){return(e?1:0)|(t?2:0)|(n?4:0)|(r?8:0)}this.$padding=0,this.setPadding=function(e){this.$padding=e},this.setSession=function(e){this.session=e},this.setMarkers=function(e){this.markers=e},this.elt=function(e,t){var n=this.i!=-1&&this.element.childNodes[this.i];n?this.i++:(n=document.createElement("div"),this.element.appendChild(n),this.i=-1),n.style.cssText=t,n.className=e},this.update=function(e){if(!e)return;this.config=e,this.i=0;var t;for(var n in this.markers){var r=this.markers[n];if(!r.range){r.update(t,this,this.session,e);continue}var i=r.range.clipRows(e.firstRow,e.lastRow);if(i.isEmpty())continue;i=i.toScreenRange(this.session);if(r.renderer){var s=this.$getTop(i.start.row,e),o=this.$padding+i.start.column*e.characterWidth;r.renderer(t,i,o,s,e)}else r.type=="fullLine"?this.drawFullLineMarker(t,i,r.clazz,e):r.type=="screenLine"?this.drawScreenLineMarker(t,i,r.clazz,e):i.isMultiLine()?r.type=="text"?this.drawTextMarker(t,i,r.clazz,e):this.drawMultiLineMarker(t,i,r.clazz,e):this.drawSingleLineMarker(t,i,r.clazz+" ace_start"+" ace_br15",e)}if(this.i!=-1)while(this.ip,l==f),s,l==f?0:1,o)},this.drawMultiLineMarker=function(e,t,n,r,i){var s=this.$padding,o=r.lineHeight,u=this.$getTop(t.start.row,r),a=s+t.start.column*r.characterWidth;i=i||"";if(this.session.$bidiHandler.isBidiRow(t.start.row)){var f=t.clone();f.end.row=f.start.row,f.end.column=this.session.getLine(f.start.row).length,this.drawBidiSingleLineMarker(e,f,n+" ace_br1 ace_start",r,null,i)}else this.elt(n+" ace_br1 ace_start","height:"+o+"px;"+"right:0;"+"top:"+u+"px;left:"+a+"px;"+(i||""));if(this.session.$bidiHandler.isBidiRow(t.end.row)){var f=t.clone();f.start.row=f.end.row,f.start.column=0,this.drawBidiSingleLineMarker(e,f,n+" ace_br12",r,null,i)}else{u=this.$getTop(t.end.row,r);var l=t.end.column*r.characterWidth;this.elt(n+" ace_br12","height:"+o+"px;"+"width:"+l+"px;"+"top:"+u+"px;"+"left:"+s+"px;"+(i||""))}o=(t.end.row-t.start.row-1)*r.lineHeight;if(o<=0)return;u=this.$getTop(t.start.row+1,r);var c=(t.start.column?1:0)|(t.end.column?0:8);this.elt(n+(c?" ace_br"+c:""),"height:"+o+"px;"+"right:0;"+"top:"+u+"px;"+"left:"+s+"px;"+(i||""))},this.drawSingleLineMarker=function(e,t,n,r,i,s){if(this.session.$bidiHandler.isBidiRow(t.start.row))return this.drawBidiSingleLineMarker(e,t,n,r,i,s);var o=r.lineHeight,u=(t.end.column+(i||0)-t.start.column)*r.characterWidth,a=this.$getTop(t.start.row,r),f=this.$padding+t.start.column*r.characterWidth;this.elt(n,"height:"+o+"px;"+"width:"+u+"px;"+"top:"+a+"px;"+"left:"+f+"px;"+(s||""))},this.drawBidiSingleLineMarker=function(e,t,n,r,i,s){var o=r.lineHeight,u=this.$getTop(t.start.row,r),a=this.$padding,f=this.session.$bidiHandler.getSelections(t.start.column,t.end.column);f.forEach(function(e){this.elt(n,"height:"+o+"px;"+"width:"+e.width+(i||0)+"px;"+"top:"+u+"px;"+"left:"+(a+e.left)+"px;"+(s||""))},this)},this.drawFullLineMarker=function(e,t,n,r,i){var s=this.$getTop(t.start.row,r),o=r.lineHeight;t.start.row!=t.end.row&&(o+=this.$getTop(t.end.row,r)-s),this.elt(n,"height:"+o+"px;"+"top:"+s+"px;"+"left:0;right:0;"+(i||""))},this.drawScreenLineMarker=function(e,t,n,r,i){var s=this.$getTop(t.start.row,r),o=r.lineHeight;this.elt(n,"height:"+o+"px;"+"top:"+s+"px;"+"left:0;right:0;"+(i||""))}}).call(s.prototype),t.Marker=s}),define("ace/layer/text",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/lib/lang","ace/layer/lines","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("../lib/dom"),s=e("../lib/lang"),o=e("./lines").Lines,u=e("../lib/event_emitter").EventEmitter,a=function(e){this.dom=i,this.element=this.dom.createElement("div"),this.element.className="ace_layer ace_text-layer",e.appendChild(this.element),this.$updateEolChar=this.$updateEolChar.bind(this),this.$lines=new o(this.element)};(function(){r.implement(this,u),this.EOF_CHAR="\u00b6",this.EOL_CHAR_LF="\u00ac",this.EOL_CHAR_CRLF="\u00a4",this.EOL_CHAR=this.EOL_CHAR_LF,this.TAB_CHAR="\u2014",this.SPACE_CHAR="\u00b7",this.$padding=0,this.MAX_LINE_LENGTH=1e4,this.$updateEolChar=function(){var e=this.session.doc,t=e.getNewLineCharacter()=="\n"&&e.getNewLineMode()!="windows",n=t?this.EOL_CHAR_LF:this.EOL_CHAR_CRLF;if(this.EOL_CHAR!=n)return this.EOL_CHAR=n,!0},this.setPadding=function(e){this.$padding=e,this.element.style.margin="0 "+e+"px"},this.getLineHeight=function(){return this.$fontMetrics.$characterSize.height||0},this.getCharacterWidth=function(){return this.$fontMetrics.$characterSize.width||0},this.$setFontMetrics=function(e){this.$fontMetrics=e,this.$fontMetrics.on("changeCharacterSize",function(e){this._signal("changeCharacterSize",e)}.bind(this)),this.$pollSizeChanges()},this.checkForSizeChanges=function(){this.$fontMetrics.checkForSizeChanges()},this.$pollSizeChanges=function(){return this.$pollSizeChangesTimer=this.$fontMetrics.$pollSizeChanges()},this.setSession=function(e){this.session=e,e&&this.$computeTabString()},this.showInvisibles=!1,this.showSpaces=!1,this.showTabs=!1,this.showEOL=!1,this.setShowInvisibles=function(e){return this.showInvisibles==e?!1:(this.showInvisibles=e,typeof e=="string"?(this.showSpaces=/tab/i.test(e),this.showTabs=/space/i.test(e),this.showEOL=/eol/i.test(e)):this.showSpaces=this.showTabs=this.showEOL=e,this.$computeTabString(),!0)},this.displayIndentGuides=!0,this.setDisplayIndentGuides=function(e){return this.displayIndentGuides==e?!1:(this.displayIndentGuides=e,this.$computeTabString(),!0)},this.$tabStrings=[],this.onChangeTabSize=this.$computeTabString=function(){var e=this.session.getTabSize();this.tabSize=e;var t=this.$tabStrings=[0];for(var n=1;nl&&(u=a.end.row+1,a=this.session.getNextFoldLine(u,a),l=a?a.start.row:Infinity);if(u>i)break;var c=s[o++];if(c){this.dom.removeChildren(c),this.$renderLine(c,u,u==l?a:!1),f&&(c.style.top=this.$lines.computeLineTop(u,e,this.session)+"px");var h=e.lineHeight*this.session.getRowLength(u)+"px";c.style.height!=h&&(f=!0,c.style.height=h)}u++}if(f)while(o0;i--)this.$lines.shift();if(t.lastRow>e.lastRow)for(var i=this.session.getFoldedRowCount(e.lastRow+1,t.lastRow);i>0;i--)this.$lines.pop();e.firstRowt.lastRow&&this.$lines.push(this.$renderLinesFragment(e,t.lastRow+1,e.lastRow))},this.$renderLinesFragment=function(e,t,n){var r=[],s=t,o=this.session.getNextFoldLine(s),u=o?o.start.row:Infinity;for(;;){s>u&&(s=o.end.row+1,o=this.session.getNextFoldLine(s,o),u=o?o.start.row:Infinity);if(s>n)break;var a=this.$lines.createCell(s,e,this.session),f=a.element;this.dom.removeChildren(f),i.setStyle(f.style,"height",this.$lines.computeLineHeight(s,e,this.session)+"px"),i.setStyle(f.style,"top",this.$lines.computeLineTop(s,e,this.session)+"px"),this.$renderLine(f,s,s==u?o:!1),this.$useLineGroups()?f.className="ace_line_group":f.className="ace_line",r.push(a),s++}return r},this.update=function(e){this.$lines.moveContainer(e),this.config=e;var t=e.firstRow,n=e.lastRow,r=this.$lines;while(r.getLength())r.pop();r.push(this.$renderLinesFragment(e,t,n))},this.$textToken={text:!0,rparen:!0,lparen:!0},this.$renderToken=function(e,t,n,r){var i=this,o=/(\t)|( +)|([\x00-\x1f\x80-\xa0\xad\u1680\u180E\u2000-\u200f\u2028\u2029\u202F\u205F\uFEFF\uFFF9-\uFFFC]+)|(\u3000)|([\u1100-\u115F\u11A3-\u11A7\u11FA-\u11FF\u2329-\u232A\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFB\u3001-\u303E\u3041-\u3096\u3099-\u30FF\u3105-\u312D\u3131-\u318E\u3190-\u31BA\u31C0-\u31E3\u31F0-\u321E\u3220-\u3247\u3250-\u32FE\u3300-\u4DBF\u4E00-\uA48C\uA490-\uA4C6\uA960-\uA97C\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFAFF\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE66\uFE68-\uFE6B\uFF01-\uFF60\uFFE0-\uFFE6]|[\uD800-\uDBFF][\uDC00-\uDFFF])/g,u=this.dom.createFragment(this.element),a,f=0;while(a=o.exec(r)){var l=a[1],c=a[2],h=a[3],p=a[4],d=a[5];if(!i.showSpaces&&c)continue;var v=f!=a.index?r.slice(f,a.index):"";f=a.index+a[0].length,v&&u.appendChild(this.dom.createTextNode(v,this.element));if(l){var m=i.session.getScreenTabSize(t+a.index);u.appendChild(i.$tabStrings[m].cloneNode(!0)),t+=m-1}else if(c)if(i.showSpaces){var g=this.dom.createElement("span");g.className="ace_invisible ace_invisible_space",g.textContent=s.stringRepeat(i.SPACE_CHAR,c.length),u.appendChild(g)}else u.appendChild(this.com.createTextNode(c,this.element));else if(h){var g=this.dom.createElement("span");g.className="ace_invisible ace_invisible_space ace_invalid",g.textContent=s.stringRepeat(i.SPACE_CHAR,h.length),u.appendChild(g)}else if(p){t+=1;var g=this.dom.createElement("span");g.style.width=i.config.characterWidth*2+"px",g.className=i.showSpaces?"ace_cjk ace_invisible ace_invisible_space":"ace_cjk",g.textContent=i.showSpaces?i.SPACE_CHAR:p,u.appendChild(g)}else if(d){t+=1;var g=this.dom.createElement("span");g.style.width=i.config.characterWidth*2+"px",g.className="ace_cjk",g.textContent=d,u.appendChild(g)}}u.appendChild(this.dom.createTextNode(f?r.slice(f):r,this.element));if(!this.$textToken[n.type]){var y="ace_"+n.type.replace(/\./g," ace_"),g=this.dom.createElement("span");n.type=="fold"&&(g.style.width=n.value.length*this.config.characterWidth+"px"),g.className=y,g.appendChild(u),e.appendChild(g)}else e.appendChild(u);return t+r.length},this.renderIndentGuide=function(e,t,n){var r=t.search(this.$indentGuideRe);if(r<=0||r>=n)return t;if(t[0]==" "){r-=r%this.tabSize;var i=r/this.tabSize;for(var s=0;s=o)u=this.$renderToken(a,u,l,c.substring(0,o-r)),c=c.substring(o-r),r=o,a=this.$createLineElement(),e.appendChild(a),a.appendChild(this.dom.createTextNode(s.stringRepeat("\u00a0",n.indent),this.element)),i++,u=0,o=n[i]||Number.MAX_VALUE;c.length!=0&&(r+=c.length,u=this.$renderToken(a,u,l,c))}}n[n.length-1]>this.MAX_LINE_LENGTH&&this.$renderOverflowMessage(a,u,null,"",!0)},this.$renderSimpleLine=function(e,t){var n=0,r=t[0],i=r.value;this.displayIndentGuides&&(i=this.renderIndentGuide(e,i)),i&&(n=this.$renderToken(e,n,r,i));for(var s=1;sthis.MAX_LINE_LENGTH)return this.$renderOverflowMessage(e,n,r,i);n=this.$renderToken(e,n,r,i)}},this.$renderOverflowMessage=function(e,t,n,r,i){n&&this.$renderToken(e,t,n,r.slice(0,this.MAX_LINE_LENGTH-t));var s=this.dom.createElement("span");s.className="ace_inline_button ace_keyword ace_toggle_wrap",s.textContent=i?"":"",e.appendChild(s)},this.$renderLine=function(e,t,n){!n&&n!=0&&(n=this.session.getFoldLine(t));if(n)var r=this.$getFoldLineTokens(t,n);else var r=this.session.getTokens(t);var i=e;if(r.length){var s=this.session.getRowSplitData(t);if(s&&s.length){this.$renderWrappedLine(e,r,s);var i=e.lastChild}else{var i=e;this.$useLineGroups()&&(i=this.$createLineElement(),e.appendChild(i)),this.$renderSimpleLine(i,r)}}else this.$useLineGroups()&&(i=this.$createLineElement(),e.appendChild(i));if(this.showEOL&&i){n&&(t=n.end.row);var o=this.dom.createElement("span");o.className="ace_invisible ace_invisible_eol",o.textContent=t==this.session.getLength()-1?this.EOF_CHAR:this.EOL_CHAR,i.appendChild(o)}},this.$getFoldLineTokens=function(e,t){function i(e,t,n){var i=0,s=0;while(s+e[i].value.lengthn-t&&(o=o.substring(0,n-t)),r.push({type:e[i].type,value:o}),s=t+o.length,i+=1}while(sn?r.push({type:e[i].type,value:o.substring(0,n-s)}):r.push(e[i]),s+=o.length,i+=1}}var n=this.session,r=[],s=n.getTokens(e);return t.walk(function(e,t,o,u,a){e!=null?r.push({type:"fold",value:e}):(a&&(s=n.getTokens(t)),s.length&&i(s,u,o))},t.end.row,this.session.getLine(t.end.row).length),r},this.$useLineGroups=function(){return this.session.getUseWrapMode()},this.destroy=function(){}}).call(a.prototype),t.Text=a}),define("ace/layer/cursor",["require","exports","module","ace/lib/dom"],function(e,t,n){"use strict";var r=e("../lib/dom"),i=function(e){this.element=r.createElement("div"),this.element.className="ace_layer ace_cursor-layer",e.appendChild(this.element),this.isVisible=!1,this.isBlinking=!0,this.blinkInterval=1e3,this.smoothBlinking=!1,this.cursors=[],this.cursor=this.addCursor(),r.addCssClass(this.element,"ace_hidden-cursors"),this.$updateCursors=this.$updateOpacity.bind(this)};(function(){this.$updateOpacity=function(e){var t=this.cursors;for(var n=t.length;n--;)r.setStyle(t[n].style,"opacity",e?"":"0")},this.$startCssAnimation=function(){var e=this.cursors;for(var t=e.length;t--;)e[t].style.animationDuration=this.blinkInterval+"ms";this.$isAnimating=!0,setTimeout(function(){this.$isAnimating&&r.addCssClass(this.element,"ace_animate-blinking")}.bind(this))},this.$stopCssAnimation=function(){this.$isAnimating=!1,r.removeCssClass(this.element,"ace_animate-blinking")},this.$padding=0,this.setPadding=function(e){this.$padding=e},this.setSession=function(e){this.session=e},this.setBlinking=function(e){e!=this.isBlinking&&(this.isBlinking=e,this.restartTimer())},this.setBlinkInterval=function(e){e!=this.blinkInterval&&(this.blinkInterval=e,this.restartTimer())},this.setSmoothBlinking=function(e){e!=this.smoothBlinking&&(this.smoothBlinking=e,r.setCssClass(this.element,"ace_smooth-blinking",e),this.$updateCursors(!0),this.restartTimer())},this.addCursor=function(){var e=r.createElement("div");return e.className="ace_cursor",this.element.appendChild(e),this.cursors.push(e),e},this.removeCursor=function(){if(this.cursors.length>1){var e=this.cursors.pop();return e.parentNode.removeChild(e),e}},this.hideCursor=function(){this.isVisible=!1,r.addCssClass(this.element,"ace_hidden-cursors"),this.restartTimer()},this.showCursor=function(){this.isVisible=!0,r.removeCssClass(this.element,"ace_hidden-cursors"),this.restartTimer()},this.restartTimer=function(){var e=this.$updateCursors;clearInterval(this.intervalId),clearTimeout(this.timeoutId),this.$stopCssAnimation(),this.smoothBlinking&&(this.$isSmoothBlinking=!1,r.removeCssClass(this.element,"ace_smooth-blinking")),e(!0);if(!this.isBlinking||!this.blinkInterval||!this.isVisible){this.$stopCssAnimation();return}this.smoothBlinking&&(this.$isSmoothBlinking=!0,setTimeout(function(){this.$isSmoothBlinking&&r.addCssClass(this.element,"ace_smooth-blinking")}.bind(this)));if(r.HAS_CSS_ANIMATION)this.$startCssAnimation();else{var t=function(){this.timeoutId=setTimeout(function(){e(!1)},.6*this.blinkInterval)}.bind(this);this.intervalId=setInterval(function(){e(!0),t()},this.blinkInterval),t()}},this.getPixelPosition=function(e,t){if(!this.config||!this.session)return{left:0,top:0};e||(e=this.session.selection.getCursor());var n=this.session.documentToScreenPosition(e),r=this.$padding+(this.session.$bidiHandler.isBidiRow(n.row,e.row)?this.session.$bidiHandler.getPosLeft(n.column):n.column*this.config.characterWidth),i=(n.row-(t?this.config.firstRowScreen:0))*this.config.lineHeight;return{left:r,top:i}},this.isCursorInView=function(e,t){return e.top>=0&&e.tope.height+e.offset||o.top<0)&&n>1)continue;var u=this.cursors[i++]||this.addCursor(),a=u.style;this.drawCursor?this.drawCursor(u,o,e,t[n],this.session):this.isCursorInView(o,e)?(r.setStyle(a,"display","block"),r.translate(u,o.left,o.top),r.setStyle(a,"width",Math.round(e.characterWidth)+"px"),r.setStyle(a,"height",e.lineHeight+"px")):r.setStyle(a,"display","none")}while(this.cursors.length>i)this.removeCursor();var f=this.session.getOverwrite();this.$setOverwrite(f),this.$pixelPos=o,this.restartTimer()},this.drawCursor=null,this.$setOverwrite=function(e){e!=this.overwrite&&(this.overwrite=e,e?r.addCssClass(this.element,"ace_overwrite-cursors"):r.removeCssClass(this.element,"ace_overwrite-cursors"))},this.destroy=function(){clearInterval(this.intervalId),clearTimeout(this.timeoutId)}}).call(i.prototype),t.Cursor=i}),define("ace/scrollbar",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/lib/event","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/dom"),s=e("./lib/event"),o=e("./lib/event_emitter").EventEmitter,u=32768,a=function(e){this.element=i.createElement("div"),this.element.className="ace_scrollbar ace_scrollbar"+this.classSuffix,this.inner=i.createElement("div"),this.inner.className="ace_scrollbar-inner",this.inner.textContent="\u00a0",this.element.appendChild(this.inner),e.appendChild(this.element),this.setVisible(!1),this.skipEvent=!1,s.addListener(this.element,"scroll",this.onScroll.bind(this)),s.addListener(this.element,"mousedown",s.preventDefault)};(function(){r.implement(this,o),this.setVisible=function(e){this.element.style.display=e?"":"none",this.isVisible=e,this.coeff=1}}).call(a.prototype);var f=function(e,t){a.call(this,e),this.scrollTop=0,this.scrollHeight=0,t.$scrollbarWidth=this.width=i.scrollbarWidth(e.ownerDocument),this.inner.style.width=this.element.style.width=(this.width||15)+5+"px",this.$minWidth=0};r.inherits(f,a),function(){this.classSuffix="-v",this.onScroll=function(){if(!this.skipEvent){this.scrollTop=this.element.scrollTop;if(this.coeff!=1){var e=this.element.clientHeight/this.scrollHeight;this.scrollTop=this.scrollTop*(1-e)/(this.coeff-e)}this._emit("scroll",{data:this.scrollTop})}this.skipEvent=!1},this.getWidth=function(){return Math.max(this.isVisible?this.width:0,this.$minWidth||0)},this.setHeight=function(e){this.element.style.height=e+"px"},this.setInnerHeight=this.setScrollHeight=function(e){this.scrollHeight=e,e>u?(this.coeff=u/e,e=u):this.coeff!=1&&(this.coeff=1),this.inner.style.height=e+"px"},this.setScrollTop=function(e){this.scrollTop!=e&&(this.skipEvent=!0,this.scrollTop=e,this.element.scrollTop=e*this.coeff)}}.call(f.prototype);var l=function(e,t){a.call(this,e),this.scrollLeft=0,this.height=t.$scrollbarWidth,this.inner.style.height=this.element.style.height=(this.height||15)+5+"px"};r.inherits(l,a),function(){this.classSuffix="-h",this.onScroll=function(){this.skipEvent||(this.scrollLeft=this.element.scrollLeft,this._emit("scroll",{data:this.scrollLeft})),this.skipEvent=!1},this.getHeight=function(){return this.isVisible?this.height:0},this.setWidth=function(e){this.element.style.width=e+"px"},this.setInnerWidth=function(e){this.inner.style.width=e+"px"},this.setScrollWidth=function(e){this.inner.style.width=e+"px"},this.setScrollLeft=function(e){this.scrollLeft!=e&&(this.skipEvent=!0,this.scrollLeft=this.element.scrollLeft=e)}}.call(l.prototype),t.ScrollBar=f,t.ScrollBarV=f,t.ScrollBarH=l,t.VScrollBar=f,t.HScrollBar=l}),define("ace/renderloop",["require","exports","module","ace/lib/event"],function(e,t,n){"use strict";var r=e("./lib/event"),i=function(e,t){this.onRender=e,this.pending=!1,this.changes=0,this.$recursionLimit=2,this.window=t||window;var n=this;this._flush=function(e){n.pending=!1;var t=n.changes;t&&(r.blockIdle(100),n.changes=0,n.onRender(t));if(n.changes){if(n.$recursionLimit--<0)return;n.schedule()}else n.$recursionLimit=2}};(function(){this.schedule=function(e){this.changes=this.changes|e,this.changes&&!this.pending&&(r.nextFrame(this._flush),this.pending=!0)},this.clear=function(e){var t=this.changes;return this.changes=0,t}}).call(i.prototype),t.RenderLoop=i}),define("ace/layer/font_metrics",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/lib/lang","ace/lib/event","ace/lib/useragent","ace/lib/event_emitter"],function(e,t,n){var r=e("../lib/oop"),i=e("../lib/dom"),s=e("../lib/lang"),o=e("../lib/event"),u=e("../lib/useragent"),a=e("../lib/event_emitter").EventEmitter,f=256,l=typeof ResizeObserver=="function",c=200,h=t.FontMetrics=function(e){this.el=i.createElement("div"),this.$setMeasureNodeStyles(this.el.style,!0),this.$main=i.createElement("div"),this.$setMeasureNodeStyles(this.$main.style),this.$measureNode=i.createElement("div"),this.$setMeasureNodeStyles(this.$measureNode.style),this.el.appendChild(this.$main),this.el.appendChild(this.$measureNode),e.appendChild(this.el),this.$measureNode.textContent=s.stringRepeat("X",f),this.$characterSize={width:0,height:0},l?this.$addObserver():this.checkForSizeChanges()};(function(){r.implement(this,a),this.$characterSize={width:0,height:0},this.$setMeasureNodeStyles=function(e,t){e.width=e.height="auto",e.left=e.top="0px",e.visibility="hidden",e.position="absolute",e.whiteSpace="pre",u.isIE<8?e["font-family"]="inherit":e.font="inherit",e.overflow=t?"hidden":"visible"},this.checkForSizeChanges=function(e){e===undefined&&(e=this.$measureSizes());if(e&&(this.$characterSize.width!==e.width||this.$characterSize.height!==e.height)){this.$measureNode.style.fontWeight="bold";var t=this.$measureSizes();this.$measureNode.style.fontWeight="",this.$characterSize=e,this.charSizes=Object.create(null),this.allowBoldFonts=t&&t.width===e.width&&t.height===e.height,this._emit("changeCharacterSize",{data:e})}},this.$addObserver=function(){var e=this;this.$observer=new window.ResizeObserver(function(t){e.checkForSizeChanges()}),this.$observer.observe(this.$measureNode)},this.$pollSizeChanges=function(){if(this.$pollSizeChangesTimer||this.$observer)return this.$pollSizeChangesTimer;var e=this;return this.$pollSizeChangesTimer=o.onIdle(function t(){e.checkForSizeChanges(),o.onIdle(t,500)},500)},this.setPolling=function(e){e?this.$pollSizeChanges():this.$pollSizeChangesTimer&&(clearInterval(this.$pollSizeChangesTimer),this.$pollSizeChangesTimer=0)},this.$measureSizes=function(e){var t={height:(e||this.$measureNode).clientHeight,width:(e||this.$measureNode).clientWidth/f};return t.width===0||t.height===0?null:t},this.$measureCharWidth=function(e){this.$main.textContent=s.stringRepeat(e,f);var t=this.$main.getBoundingClientRect();return t.width/f},this.getCharacterWidth=function(e){var t=this.charSizes[e];return t===undefined&&(t=this.charSizes[e]=this.$measureCharWidth(e)/this.$characterSize.width),t},this.destroy=function(){clearInterval(this.$pollSizeChangesTimer),this.$observer&&this.$observer.disconnect(),this.el&&this.el.parentNode&&this.el.parentNode.removeChild(this.el)},this.$getZoom=function e(t){return!t||!t.parentElement?1:(window.getComputedStyle(t).zoom||1)*e(t.parentElement)},this.$initTransformMeasureNodes=function(){var e=function(e,t){return["div",{style:"position: absolute;top:"+e+"px;left:"+t+"px;"}]};this.els=i.buildDom([e(0,0),e(c,0),e(0,c),e(c,c)],this.el)},this.transformCoordinates=function(e,t){function r(e,t,n){var r=e[1]*t[0]-e[0]*t[1];return[(-t[1]*n[0]+t[0]*n[1])/r,(+e[1]*n[0]-e[0]*n[1])/r]}function i(e,t){return[e[0]-t[0],e[1]-t[1]]}function s(e,t){return[e[0]+t[0],e[1]+t[1]]}function o(e,t){return[e*t[0],e*t[1]]}function u(e){var t=e.getBoundingClientRect();return[t.left,t.top]}if(e){var n=this.$getZoom(this.el);e=o(1/n,e)}this.els||this.$initTransformMeasureNodes();var a=u(this.els[0]),f=u(this.els[1]),l=u(this.els[2]),h=u(this.els[3]),p=r(i(h,f),i(h,l),i(s(f,l),s(h,a))),d=o(1+p[0],i(f,a)),v=o(1+p[1],i(l,a));if(t){var m=t,g=p[0]*m[0]/c+p[1]*m[1]/c+1,y=s(o(m[0],d),o(m[1],v));return s(o(1/g/c,y),a)}var b=i(e,a),w=r(i(d,o(p[0],b)),i(v,o(p[1],b)),b);return o(c,w)}}).call(h.prototype)}),define("ace/virtual_renderer",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/config","ace/layer/gutter","ace/layer/marker","ace/layer/text","ace/layer/cursor","ace/scrollbar","ace/scrollbar","ace/renderloop","ace/layer/font_metrics","ace/lib/event_emitter","ace/lib/useragent"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/dom"),s=e("./config"),o=e("./layer/gutter").Gutter,u=e("./layer/marker").Marker,a=e("./layer/text").Text,f=e("./layer/cursor").Cursor,l=e("./scrollbar").HScrollBar,c=e("./scrollbar").VScrollBar,h=e("./renderloop").RenderLoop,p=e("./layer/font_metrics").FontMetrics,d=e("./lib/event_emitter").EventEmitter,v='.ace_br1 {border-top-left-radius : 3px;}.ace_br2 {border-top-right-radius : 3px;}.ace_br3 {border-top-left-radius : 3px; border-top-right-radius: 3px;}.ace_br4 {border-bottom-right-radius: 3px;}.ace_br5 {border-top-left-radius : 3px; border-bottom-right-radius: 3px;}.ace_br6 {border-top-right-radius : 3px; border-bottom-right-radius: 3px;}.ace_br7 {border-top-left-radius : 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px;}.ace_br8 {border-bottom-left-radius : 3px;}.ace_br9 {border-top-left-radius : 3px; border-bottom-left-radius: 3px;}.ace_br10{border-top-right-radius : 3px; border-bottom-left-radius: 3px;}.ace_br11{border-top-left-radius : 3px; border-top-right-radius: 3px; border-bottom-left-radius: 3px;}.ace_br12{border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}.ace_br13{border-top-left-radius : 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}.ace_br14{border-top-right-radius : 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}.ace_br15{border-top-left-radius : 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}.ace_editor {position: relative;overflow: hidden;padding: 0;font: 12px/normal \'Monaco\', \'Menlo\', \'Ubuntu Mono\', \'Consolas\', \'source-code-pro\', monospace;direction: ltr;text-align: left;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);}.ace_scroller {position: absolute;overflow: hidden;top: 0;bottom: 0;background-color: inherit;-ms-user-select: none;-moz-user-select: none;-webkit-user-select: none;user-select: none;cursor: text;}.ace_content {position: absolute;box-sizing: border-box;min-width: 100%;contain: style size layout;font-variant-ligatures: no-common-ligatures;}.ace_dragging .ace_scroller:before{position: absolute;top: 0;left: 0;right: 0;bottom: 0;content: \'\';background: rgba(250, 250, 250, 0.01);z-index: 1000;}.ace_dragging.ace_dark .ace_scroller:before{background: rgba(0, 0, 0, 0.01);}.ace_selecting, .ace_selecting * {cursor: text !important;}.ace_gutter {position: absolute;overflow : hidden;width: auto;top: 0;bottom: 0;left: 0;cursor: default;z-index: 4;-ms-user-select: none;-moz-user-select: none;-webkit-user-select: none;user-select: none;contain: style size layout;}.ace_gutter-active-line {position: absolute;left: 0;right: 0;}.ace_scroller.ace_scroll-left {box-shadow: 17px 0 16px -16px rgba(0, 0, 0, 0.4) inset;}.ace_gutter-cell {position: absolute;top: 0;left: 0;right: 0;padding-left: 19px;padding-right: 6px;background-repeat: no-repeat;}.ace_gutter-cell.ace_error {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABOFBMVEX/////////QRswFAb/Ui4wFAYwFAYwFAaWGAfDRymzOSH/PxswFAb/SiUwFAYwFAbUPRvjQiDllog5HhHdRybsTi3/Tyv9Tir+Syj/UC3////XurebMBIwFAb/RSHbPx/gUzfdwL3kzMivKBAwFAbbvbnhPx66NhowFAYwFAaZJg8wFAaxKBDZurf/RB6mMxb/SCMwFAYwFAbxQB3+RB4wFAb/Qhy4Oh+4QifbNRcwFAYwFAYwFAb/QRzdNhgwFAYwFAbav7v/Uy7oaE68MBK5LxLewr/r2NXewLswFAaxJw4wFAbkPRy2PyYwFAaxKhLm1tMwFAazPiQwFAaUGAb/QBrfOx3bvrv/VC/maE4wFAbRPBq6MRO8Qynew8Dp2tjfwb0wFAbx6eju5+by6uns4uH9/f36+vr/GkHjAAAAYnRSTlMAGt+64rnWu/bo8eAA4InH3+DwoN7j4eLi4xP99Nfg4+b+/u9B/eDs1MD1mO7+4PHg2MXa347g7vDizMLN4eG+Pv7i5evs/v79yu7S3/DV7/498Yv24eH+4ufQ3Ozu/v7+y13sRqwAAADLSURBVHjaZc/XDsFgGIBhtDrshlitmk2IrbHFqL2pvXf/+78DPokj7+Fz9qpU/9UXJIlhmPaTaQ6QPaz0mm+5gwkgovcV6GZzd5JtCQwgsxoHOvJO15kleRLAnMgHFIESUEPmawB9ngmelTtipwwfASilxOLyiV5UVUyVAfbG0cCPHig+GBkzAENHS0AstVF6bacZIOzgLmxsHbt2OecNgJC83JERmePUYq8ARGkJx6XtFsdddBQgZE2nPR6CICZhawjA4Fb/chv+399kfR+MMMDGOQAAAABJRU5ErkJggg==");background-repeat: no-repeat;background-position: 2px center;}.ace_gutter-cell.ace_warning {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAmVBMVEX///8AAAD///8AAAAAAABPSzb/5sAAAAB/blH/73z/ulkAAAAAAAD85pkAAAAAAAACAgP/vGz/rkDerGbGrV7/pkQICAf////e0IsAAAD/oED/qTvhrnUAAAD/yHD/njcAAADuv2r/nz//oTj/p064oGf/zHAAAAA9Nir/tFIAAAD/tlTiuWf/tkIAAACynXEAAAAAAAAtIRW7zBpBAAAAM3RSTlMAABR1m7RXO8Ln31Z36zT+neXe5OzooRDfn+TZ4p3h2hTf4t3k3ucyrN1K5+Xaks52Sfs9CXgrAAAAjklEQVR42o3PbQ+CIBQFYEwboPhSYgoYunIqqLn6/z8uYdH8Vmdnu9vz4WwXgN/xTPRD2+sgOcZjsge/whXZgUaYYvT8QnuJaUrjrHUQreGczuEafQCO/SJTufTbroWsPgsllVhq3wJEk2jUSzX3CUEDJC84707djRc5MTAQxoLgupWRwW6UB5fS++NV8AbOZgnsC7BpEAAAAABJRU5ErkJggg==");background-position: 2px center;}.ace_gutter-cell.ace_info {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAJ0Uk5TAAB2k804AAAAPklEQVQY02NgIB68QuO3tiLznjAwpKTgNyDbMegwisCHZUETUZV0ZqOquBpXj2rtnpSJT1AEnnRmL2OgGgAAIKkRQap2htgAAAAASUVORK5CYII=");background-position: 2px center;}.ace_dark .ace_gutter-cell.ace_info {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJFBMVEUAAAChoaGAgIAqKiq+vr6tra1ZWVmUlJSbm5s8PDxubm56enrdgzg3AAAAAXRSTlMAQObYZgAAAClJREFUeNpjYMAPdsMYHegyJZFQBlsUlMFVCWUYKkAZMxZAGdxlDMQBAG+TBP4B6RyJAAAAAElFTkSuQmCC");}.ace_scrollbar {contain: strict;position: absolute;right: 0;bottom: 0;z-index: 6;}.ace_scrollbar-inner {position: absolute;cursor: text;left: 0;top: 0;}.ace_scrollbar-v{overflow-x: hidden;overflow-y: scroll;top: 0;}.ace_scrollbar-h {overflow-x: scroll;overflow-y: hidden;left: 0;}.ace_print-margin {position: absolute;height: 100%;}.ace_text-input {position: absolute;z-index: 0;width: 0.5em;height: 1em;opacity: 0;background: transparent;-moz-appearance: none;appearance: none;border: none;resize: none;outline: none;overflow: hidden;font: inherit;padding: 0 1px;margin: 0 -1px;contain: strict;-ms-user-select: text;-moz-user-select: text;-webkit-user-select: text;user-select: text;white-space: pre!important;}.ace_text-input.ace_composition {background: transparent;color: inherit;z-index: 1000;opacity: 1;}.ace_composition_placeholder { color: transparent }.ace_composition_marker { border-bottom: 1px solid;position: absolute;border-radius: 0;margin-top: 1px;}[ace_nocontext=true] {transform: none!important;filter: none!important;clip-path: none!important;mask : none!important;contain: none!important;perspective: none!important;mix-blend-mode: initial!important;z-index: auto;}.ace_layer {z-index: 1;position: absolute;overflow: hidden;word-wrap: normal;white-space: pre;height: 100%;width: 100%;box-sizing: border-box;pointer-events: none;}.ace_gutter-layer {position: relative;width: auto;text-align: right;pointer-events: auto;height: 1000000px;contain: style size layout;}.ace_text-layer {font: inherit !important;position: absolute;height: 1000000px;width: 1000000px;contain: style size layout;}.ace_text-layer > .ace_line, .ace_text-layer > .ace_line_group {contain: style size layout;position: absolute;top: 0;left: 0;right: 0;}.ace_hidpi .ace_text-layer,.ace_hidpi .ace_gutter-layer,.ace_hidpi .ace_content,.ace_hidpi .ace_gutter {contain: strict;will-change: transform;}.ace_hidpi .ace_text-layer > .ace_line, .ace_hidpi .ace_text-layer > .ace_line_group {contain: strict;}.ace_cjk {display: inline-block;text-align: center;}.ace_cursor-layer {z-index: 4;}.ace_cursor {z-index: 4;position: absolute;box-sizing: border-box;border-left: 2px solid;transform: translatez(0);}.ace_multiselect .ace_cursor {border-left-width: 1px;}.ace_slim-cursors .ace_cursor {border-left-width: 1px;}.ace_overwrite-cursors .ace_cursor {border-left-width: 0;border-bottom: 1px solid;}.ace_hidden-cursors .ace_cursor {opacity: 0.2;}.ace_hasPlaceholder .ace_hidden-cursors .ace_cursor {opacity: 0;}.ace_smooth-blinking .ace_cursor {transition: opacity 0.18s;}.ace_animate-blinking .ace_cursor {animation-duration: 1000ms;animation-timing-function: step-end;animation-name: blink-ace-animate;animation-iteration-count: infinite;}.ace_animate-blinking.ace_smooth-blinking .ace_cursor {animation-duration: 1000ms;animation-timing-function: ease-in-out;animation-name: blink-ace-animate-smooth;}@keyframes blink-ace-animate {from, to { opacity: 1; }60% { opacity: 0; }}@keyframes blink-ace-animate-smooth {from, to { opacity: 1; }45% { opacity: 1; }60% { opacity: 0; }85% { opacity: 0; }}.ace_marker-layer .ace_step, .ace_marker-layer .ace_stack {position: absolute;z-index: 3;}.ace_marker-layer .ace_selection {position: absolute;z-index: 5;}.ace_marker-layer .ace_bracket {position: absolute;z-index: 6;}.ace_marker-layer .ace_error_bracket {position: absolute;border-bottom: 1px solid #DE5555;border-radius: 0;}.ace_marker-layer .ace_active-line {position: absolute;z-index: 2;}.ace_marker-layer .ace_selected-word {position: absolute;z-index: 4;box-sizing: border-box;}.ace_line .ace_fold {box-sizing: border-box;display: inline-block;height: 11px;margin-top: -2px;vertical-align: middle;background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJpJREFUeNpi/P//PwOlgAXGYGRklAVSokD8GmjwY1wasKljQpYACtpCFeADcHVQfQyMQAwzwAZI3wJKvCLkfKBaMSClBlR7BOQikCFGQEErIH0VqkabiGCAqwUadAzZJRxQr/0gwiXIal8zQQPnNVTgJ1TdawL0T5gBIP1MUJNhBv2HKoQHHjqNrA4WO4zY0glyNKLT2KIfIMAAQsdgGiXvgnYAAAAASUVORK5CYII="),url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA3CAYAAADNNiA5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACJJREFUeNpi+P//fxgTAwPDBxDxD078RSX+YeEyDFMCIMAAI3INmXiwf2YAAAAASUVORK5CYII=");background-repeat: no-repeat, repeat-x;background-position: center center, top left;color: transparent;border: 1px solid black;border-radius: 2px;cursor: pointer;pointer-events: auto;}.ace_dark .ace_fold {}.ace_fold:hover{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJpJREFUeNpi/P//PwOlgAXGYGRklAVSokD8GmjwY1wasKljQpYACtpCFeADcHVQfQyMQAwzwAZI3wJKvCLkfKBaMSClBlR7BOQikCFGQEErIH0VqkabiGCAqwUadAzZJRxQr/0gwiXIal8zQQPnNVTgJ1TdawL0T5gBIP1MUJNhBv2HKoQHHjqNrA4WO4zY0glyNKLT2KIfIMAAQsdgGiXvgnYAAAAASUVORK5CYII="),url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA3CAYAAADNNiA5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACBJREFUeNpi+P//fz4TAwPDZxDxD5X4i5fLMEwJgAADAEPVDbjNw87ZAAAAAElFTkSuQmCC");}.ace_tooltip {background-color: #FFF;background-image: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.1));border: 1px solid gray;border-radius: 1px;box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);color: black;max-width: 100%;padding: 3px 4px;position: fixed;z-index: 999999;box-sizing: border-box;cursor: default;white-space: pre;word-wrap: break-word;line-height: normal;font-style: normal;font-weight: normal;letter-spacing: normal;pointer-events: none;}.ace_folding-enabled > .ace_gutter-cell {padding-right: 13px;}.ace_fold-widget {box-sizing: border-box;margin: 0 -12px 0 1px;display: none;width: 11px;vertical-align: top;background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAANElEQVR42mWKsQ0AMAzC8ixLlrzQjzmBiEjp0A6WwBCSPgKAXoLkqSot7nN3yMwR7pZ32NzpKkVoDBUxKAAAAABJRU5ErkJggg==");background-repeat: no-repeat;background-position: center;border-radius: 3px;border: 1px solid transparent;cursor: pointer;}.ace_folding-enabled .ace_fold-widget {display: inline-block; }.ace_fold-widget.ace_end {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAANElEQVR42m3HwQkAMAhD0YzsRchFKI7sAikeWkrxwScEB0nh5e7KTPWimZki4tYfVbX+MNl4pyZXejUO1QAAAABJRU5ErkJggg==");}.ace_fold-widget.ace_closed {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAGCAYAAAAG5SQMAAAAOUlEQVR42jXKwQkAMAgDwKwqKD4EwQ26sSOkVWjgIIHAzPiCgaqiqnJHZnKICBERHN194O5b9vbLuAVRL+l0YWnZAAAAAElFTkSuQmCCXA==");}.ace_fold-widget:hover {border: 1px solid rgba(0, 0, 0, 0.3);background-color: rgba(255, 255, 255, 0.2);box-shadow: 0 1px 1px rgba(255, 255, 255, 0.7);}.ace_fold-widget:active {border: 1px solid rgba(0, 0, 0, 0.4);background-color: rgba(0, 0, 0, 0.05);box-shadow: 0 1px 1px rgba(255, 255, 255, 0.8);}.ace_dark .ace_fold-widget {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHklEQVQIW2P4//8/AzoGEQ7oGCaLLAhWiSwB146BAQCSTPYocqT0AAAAAElFTkSuQmCC");}.ace_dark .ace_fold-widget.ace_end {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAH0lEQVQIW2P4//8/AxQ7wNjIAjDMgC4AxjCVKBirIAAF0kz2rlhxpAAAAABJRU5ErkJggg==");}.ace_dark .ace_fold-widget.ace_closed {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAHElEQVQIW2P4//+/AxAzgDADlOOAznHAKgPWAwARji8UIDTfQQAAAABJRU5ErkJggg==");}.ace_dark .ace_fold-widget:hover {box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);background-color: rgba(255, 255, 255, 0.1);}.ace_dark .ace_fold-widget:active {box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);}.ace_inline_button {border: 1px solid lightgray;display: inline-block;margin: -1px 8px;padding: 0 5px;pointer-events: auto;cursor: pointer;}.ace_inline_button:hover {border-color: gray;background: rgba(200,200,200,0.2);display: inline-block;pointer-events: auto;}.ace_fold-widget.ace_invalid {background-color: #FFB4B4;border-color: #DE5555;}.ace_fade-fold-widgets .ace_fold-widget {transition: opacity 0.4s ease 0.05s;opacity: 0;}.ace_fade-fold-widgets:hover .ace_fold-widget {transition: opacity 0.05s ease 0.05s;opacity:1;}.ace_underline {text-decoration: underline;}.ace_bold {font-weight: bold;}.ace_nobold .ace_bold {font-weight: normal;}.ace_italic {font-style: italic;}.ace_error-marker {background-color: rgba(255, 0, 0,0.2);position: absolute;z-index: 9;}.ace_highlight-marker {background-color: rgba(255, 255, 0,0.2);position: absolute;z-index: 8;}.ace_mobile-menu {position: absolute;line-height: 1.5;border-radius: 4px;-ms-user-select: none;-moz-user-select: none;-webkit-user-select: none;user-select: none;background: white;box-shadow: 1px 3px 2px grey;border: 1px solid #dcdcdc;color: black;}.ace_dark > .ace_mobile-menu {background: #333;color: #ccc;box-shadow: 1px 3px 2px grey;border: 1px solid #444;}.ace_mobile-button {padding: 2px;cursor: pointer;overflow: hidden;}.ace_mobile-button:hover {background-color: #eee;opacity:1;}.ace_mobile-button:active {background-color: #ddd;}.ace_placeholder {font-family: arial;transform: scale(0.9);transform-origin: left;white-space: pre;opacity: 0.7;margin: 0 10px;}',m=e("./lib/useragent"),g=m.isIE;i.importCssString(v,"ace_editor.css",!1);var y=function(e,t){var n=this;this.container=e||i.createElement("div"),i.addCssClass(this.container,"ace_editor"),i.HI_DPI&&i.addCssClass(this.container,"ace_hidpi"),this.setTheme(t),s.get("useStrictCSP")==null&&s.set("useStrictCSP",!1),this.$gutter=i.createElement("div"),this.$gutter.className="ace_gutter",this.container.appendChild(this.$gutter),this.$gutter.setAttribute("aria-hidden",!0),this.scroller=i.createElement("div"),this.scroller.className="ace_scroller",this.container.appendChild(this.scroller),this.content=i.createElement("div"),this.content.className="ace_content",this.scroller.appendChild(this.content),this.$gutterLayer=new o(this.$gutter),this.$gutterLayer.on("changeGutterWidth",this.onGutterResize.bind(this)),this.$markerBack=new u(this.content);var r=this.$textLayer=new a(this.content);this.canvas=r.element,this.$markerFront=new u(this.content),this.$cursorLayer=new f(this.content),this.$horizScroll=!1,this.$vScroll=!1,this.scrollBar=this.scrollBarV=new c(this.container,this),this.scrollBarH=new l(this.container,this),this.scrollBarV.on("scroll",function(e){n.$scrollAnimation||n.session.setScrollTop(e.data-n.scrollMargin.top)}),this.scrollBarH.on("scroll",function(e){n.$scrollAnimation||n.session.setScrollLeft(e.data-n.scrollMargin.left)}),this.scrollTop=0,this.scrollLeft=0,this.cursorPos={row:0,column:0},this.$fontMetrics=new p(this.container),this.$textLayer.$setFontMetrics(this.$fontMetrics),this.$textLayer.on("changeCharacterSize",function(e){n.updateCharacterSize(),n.onResize(!0,n.gutterWidth,n.$size.width,n.$size.height),n._signal("changeCharacterSize",e)}),this.$size={width:0,height:0,scrollerHeight:0,scrollerWidth:0,$dirty:!0},this.layerConfig={width:1,padding:0,firstRow:0,firstRowScreen:0,lastRow:0,lineHeight:0,characterWidth:0,minHeight:1,maxHeight:1,offset:0,height:1,gutterOffset:1},this.scrollMargin={left:0,right:0,top:0,bottom:0,v:0,h:0},this.margin={left:0,right:0,top:0,bottom:0,v:0,h:0},this.$keepTextAreaAtCursor=!m.isIOS,this.$loop=new h(this.$renderChanges.bind(this),this.container.ownerDocument.defaultView),this.$loop.schedule(this.CHANGE_FULL),this.updateCharacterSize(),this.setPadding(4),s.resetOptions(this),s._signal("renderer",this)};(function(){this.CHANGE_CURSOR=1,this.CHANGE_MARKER=2,this.CHANGE_GUTTER=4,this.CHANGE_SCROLL=8,this.CHANGE_LINES=16,this.CHANGE_TEXT=32,this.CHANGE_SIZE=64,this.CHANGE_MARKER_BACK=128,this.CHANGE_MARKER_FRONT=256,this.CHANGE_FULL=512,this.CHANGE_H_SCROLL=1024,r.implement(this,d),this.updateCharacterSize=function(){this.$textLayer.allowBoldFonts!=this.$allowBoldFonts&&(this.$allowBoldFonts=this.$textLayer.allowBoldFonts,this.setStyle("ace_nobold",!this.$allowBoldFonts)),this.layerConfig.characterWidth=this.characterWidth=this.$textLayer.getCharacterWidth(),this.layerConfig.lineHeight=this.lineHeight=this.$textLayer.getLineHeight(),this.$updatePrintMargin(),i.setStyle(this.scroller.style,"line-height",this.lineHeight+"px")},this.setSession=function(e){this.session&&this.session.doc.off("changeNewLineMode",this.onChangeNewLineMode),this.session=e,e&&this.scrollMargin.top&&e.getScrollTop()<=0&&e.setScrollTop(-this.scrollMargin.top),this.$cursorLayer.setSession(e),this.$markerBack.setSession(e),this.$markerFront.setSession(e),this.$gutterLayer.setSession(e),this.$textLayer.setSession(e);if(!e)return;this.$loop.schedule(this.CHANGE_FULL),this.session.$setFontMetrics(this.$fontMetrics),this.scrollBarH.scrollLeft=this.scrollBarV.scrollTop=null,this.onChangeNewLineMode=this.onChangeNewLineMode.bind(this),this.onChangeNewLineMode(),this.session.doc.on("changeNewLineMode",this.onChangeNewLineMode)},this.updateLines=function(e,t,n){t===undefined&&(t=Infinity),this.$changedLines?(this.$changedLines.firstRow>e&&(this.$changedLines.firstRow=e),this.$changedLines.lastRowthis.layerConfig.lastRow)return;this.$loop.schedule(this.CHANGE_LINES)},this.onChangeNewLineMode=function(){this.$loop.schedule(this.CHANGE_TEXT),this.$textLayer.$updateEolChar(),this.session.$bidiHandler.setEolChar(this.$textLayer.EOL_CHAR)},this.onChangeTabSize=function(){this.$loop.schedule(this.CHANGE_TEXT|this.CHANGE_MARKER),this.$textLayer.onChangeTabSize()},this.updateText=function(){this.$loop.schedule(this.CHANGE_TEXT)},this.updateFull=function(e){e?this.$renderChanges(this.CHANGE_FULL,!0):this.$loop.schedule(this.CHANGE_FULL)},this.updateFontSize=function(){this.$textLayer.checkForSizeChanges()},this.$changes=0,this.$updateSizeAsync=function(){this.$loop.pending?this.$size.$dirty=!0:this.onResize()},this.onResize=function(e,t,n,r){if(this.resizing>2)return;this.resizing>0?this.resizing++:this.resizing=e?1:0;var i=this.container;r||(r=i.clientHeight||i.scrollHeight),n||(n=i.clientWidth||i.scrollWidth);var s=this.$updateCachedSize(e,t,n,r);if(!this.$size.scrollerHeight||!n&&!r)return this.resizing=0;e&&(this.$gutterLayer.$padding=null),e?this.$renderChanges(s|this.$changes,!0):this.$loop.schedule(s|this.$changes),this.resizing&&(this.resizing=0),this.scrollBarH.scrollLeft=this.scrollBarV.scrollTop=null},this.$updateCachedSize=function(e,t,n,r){r-=this.$extraHeight||0;var s=0,o=this.$size,u={width:o.width,height:o.height,scrollerHeight:o.scrollerHeight,scrollerWidth:o.scrollerWidth};r&&(e||o.height!=r)&&(o.height=r,s|=this.CHANGE_SIZE,o.scrollerHeight=o.height,this.$horizScroll&&(o.scrollerHeight-=this.scrollBarH.getHeight()),this.scrollBarV.element.style.bottom=this.scrollBarH.getHeight()+"px",s|=this.CHANGE_SCROLL);if(n&&(e||o.width!=n)){s|=this.CHANGE_SIZE,o.width=n,t==null&&(t=this.$showGutter?this.$gutter.offsetWidth:0),this.gutterWidth=t,i.setStyle(this.scrollBarH.element.style,"left",t+"px"),i.setStyle(this.scroller.style,"left",t+this.margin.left+"px"),o.scrollerWidth=Math.max(0,n-t-this.scrollBarV.getWidth()-this.margin.h),i.setStyle(this.$gutter.style,"left",this.margin.left+"px");var a=this.scrollBarV.getWidth()+"px";i.setStyle(this.scrollBarH.element.style,"right",a),i.setStyle(this.scroller.style,"right",a),i.setStyle(this.scroller.style,"bottom",this.scrollBarH.getHeight());if(this.session&&this.session.getUseWrapMode()&&this.adjustWrapLimit()||e)s|=this.CHANGE_FULL}return o.$dirty=!n||!r,s&&this._signal("resize",u),s},this.onGutterResize=function(e){var t=this.$showGutter?e:0;t!=this.gutterWidth&&(this.$changes|=this.$updateCachedSize(!0,t,this.$size.width,this.$size.height)),this.session.getUseWrapMode()&&this.adjustWrapLimit()?this.$loop.schedule(this.CHANGE_FULL):this.$size.$dirty?this.$loop.schedule(this.CHANGE_FULL):this.$computeLayerConfig()},this.adjustWrapLimit=function(){var e=this.$size.scrollerWidth-this.$padding*2,t=Math.floor(e/this.characterWidth);return this.session.adjustWrapLimit(t,this.$showPrintMargin&&this.$printMarginColumn)},this.setAnimatedScroll=function(e){this.setOption("animatedScroll",e)},this.getAnimatedScroll=function(){return this.$animatedScroll},this.setShowInvisibles=function(e){this.setOption("showInvisibles",e),this.session.$bidiHandler.setShowInvisibles(e)},this.getShowInvisibles=function(){return this.getOption("showInvisibles")},this.getDisplayIndentGuides=function(){return this.getOption("displayIndentGuides")},this.setDisplayIndentGuides=function(e){this.setOption("displayIndentGuides",e)},this.setShowPrintMargin=function(e){this.setOption("showPrintMargin",e)},this.getShowPrintMargin=function(){return this.getOption("showPrintMargin")},this.setPrintMarginColumn=function(e){this.setOption("printMarginColumn",e)},this.getPrintMarginColumn=function(){return this.getOption("printMarginColumn")},this.getShowGutter=function(){return this.getOption("showGutter")},this.setShowGutter=function(e){return this.setOption("showGutter",e)},this.getFadeFoldWidgets=function(){return this.getOption("fadeFoldWidgets")},this.setFadeFoldWidgets=function(e){this.setOption("fadeFoldWidgets",e)},this.setHighlightGutterLine=function(e){this.setOption("highlightGutterLine",e)},this.getHighlightGutterLine=function(){return this.getOption("highlightGutterLine")},this.$updatePrintMargin=function(){if(!this.$showPrintMargin&&!this.$printMarginEl)return;if(!this.$printMarginEl){var e=i.createElement("div");e.className="ace_layer ace_print-margin-layer",this.$printMarginEl=i.createElement("div"),this.$printMarginEl.className="ace_print-margin",e.appendChild(this.$printMarginEl),this.content.insertBefore(e,this.content.firstChild)}var t=this.$printMarginEl.style;t.left=Math.round(this.characterWidth*this.$printMarginColumn+this.$padding)+"px",t.visibility=this.$showPrintMargin?"visible":"hidden",this.session&&this.session.$wrap==-1&&this.adjustWrapLimit()},this.getContainerElement=function(){return this.container},this.getMouseEventTarget=function(){return this.scroller},this.getTextAreaContainer=function(){return this.container},this.$moveTextAreaToCursor=function(){if(this.$isMousePressed)return;var e=this.textarea.style,t=this.$composition;if(!this.$keepTextAreaAtCursor&&!t){i.translate(this.textarea,-100,0);return}var n=this.$cursorLayer.$pixelPos;if(!n)return;t&&t.markerRange&&(n=this.$cursorLayer.getPixelPosition(t.markerRange.start,!0));var r=this.layerConfig,s=n.top,o=n.left;s-=r.offset;var u=t&&t.useTextareaForIME?this.lineHeight:g?0:1;if(s<0||s>r.height-u){i.translate(this.textarea,0,0);return}var a=1,f=this.$size.height-u;if(!t)s+=this.lineHeight;else if(t.useTextareaForIME){var l=this.textarea.value;a=this.characterWidth*this.session.$getStringScreenWidth(l)[0]}else s+=this.lineHeight+2;o-=this.scrollLeft,o>this.$size.scrollerWidth-a&&(o=this.$size.scrollerWidth-a),o+=this.gutterWidth+this.margin.left,i.setStyle(e,"height",u+"px"),i.setStyle(e,"width",a+"px"),i.translate(this.textarea,Math.min(o,this.$size.scrollerWidth-a),Math.min(s,f))},this.getFirstVisibleRow=function(){return this.layerConfig.firstRow},this.getFirstFullyVisibleRow=function(){return this.layerConfig.firstRow+(this.layerConfig.offset===0?0:1)},this.getLastFullyVisibleRow=function(){var e=this.layerConfig,t=e.lastRow,n=this.session.documentToScreenRow(t,0)*e.lineHeight;return n-this.session.getScrollTop()>e.height-e.lineHeight?t-1:t},this.getLastVisibleRow=function(){return this.layerConfig.lastRow},this.$padding=null,this.setPadding=function(e){this.$padding=e,this.$textLayer.setPadding(e),this.$cursorLayer.setPadding(e),this.$markerFront.setPadding(e),this.$markerBack.setPadding(e),this.$loop.schedule(this.CHANGE_FULL),this.$updatePrintMargin()},this.setScrollMargin=function(e,t,n,r){var i=this.scrollMargin;i.top=e|0,i.bottom=t|0,i.right=r|0,i.left=n|0,i.v=i.top+i.bottom,i.h=i.left+i.right,i.top&&this.scrollTop<=0&&this.session&&this.session.setScrollTop(-i.top),this.updateFull()},this.setMargin=function(e,t,n,r){var i=this.margin;i.top=e|0,i.bottom=t|0,i.right=r|0,i.left=n|0,i.v=i.top+i.bottom,i.h=i.left+i.right,this.$updateCachedSize(!0,this.gutterWidth,this.$size.width,this.$size.height),this.updateFull()},this.getHScrollBarAlwaysVisible=function(){return this.$hScrollBarAlwaysVisible},this.setHScrollBarAlwaysVisible=function(e){this.setOption("hScrollBarAlwaysVisible",e)},this.getVScrollBarAlwaysVisible=function(){return this.$vScrollBarAlwaysVisible},this.setVScrollBarAlwaysVisible=function(e){this.setOption("vScrollBarAlwaysVisible",e)},this.$updateScrollBarV=function(){var e=this.layerConfig.maxHeight,t=this.$size.scrollerHeight;!this.$maxLines&&this.$scrollPastEnd&&(e-=(t-this.lineHeight)*this.$scrollPastEnd,this.scrollTop>e-t&&(e=this.scrollTop+t,this.scrollBarV.scrollTop=null)),this.scrollBarV.setScrollHeight(e+this.scrollMargin.v),this.scrollBarV.setScrollTop(this.scrollTop+this.scrollMargin.top)},this.$updateScrollBarH=function(){this.scrollBarH.setScrollWidth(this.layerConfig.width+2*this.$padding+this.scrollMargin.h),this.scrollBarH.setScrollLeft(this.scrollLeft+this.scrollMargin.left)},this.$frozen=!1,this.freeze=function(){this.$frozen=!0},this.unfreeze=function(){this.$frozen=!1},this.$renderChanges=function(e,t){this.$changes&&(e|=this.$changes,this.$changes=0);if(!this.session||!this.container.offsetWidth||this.$frozen||!e&&!t){this.$changes|=e;return}if(this.$size.$dirty)return this.$changes|=e,this.onResize(!0);this.lineHeight||this.$textLayer.checkForSizeChanges(),this._signal("beforeRender",e),this.session&&this.session.$bidiHandler&&this.session.$bidiHandler.updateCharacterWidths(this.$fontMetrics);var n=this.layerConfig;if(e&this.CHANGE_FULL||e&this.CHANGE_SIZE||e&this.CHANGE_TEXT||e&this.CHANGE_LINES||e&this.CHANGE_SCROLL||e&this.CHANGE_H_SCROLL){e|=this.$computeLayerConfig()|this.$loop.clear();if(n.firstRow!=this.layerConfig.firstRow&&n.firstRowScreen==this.layerConfig.firstRowScreen){var r=this.scrollTop+(n.firstRow-this.layerConfig.firstRow)*this.lineHeight;r>0&&(this.scrollTop=r,e|=this.CHANGE_SCROLL,e|=this.$computeLayerConfig()|this.$loop.clear())}n=this.layerConfig,this.$updateScrollBarV(),e&this.CHANGE_H_SCROLL&&this.$updateScrollBarH(),i.translate(this.content,-this.scrollLeft,-n.offset);var s=n.width+2*this.$padding+"px",o=n.minHeight+"px";i.setStyle(this.content.style,"width",s),i.setStyle(this.content.style,"height",o)}e&this.CHANGE_H_SCROLL&&(i.translate(this.content,-this.scrollLeft,-n.offset),this.scroller.className=this.scrollLeft<=0?"ace_scroller":"ace_scroller ace_scroll-left");if(e&this.CHANGE_FULL){this.$changedLines=null,this.$textLayer.update(n),this.$showGutter&&this.$gutterLayer.update(n),this.$markerBack.update(n),this.$markerFront.update(n),this.$cursorLayer.update(n),this.$moveTextAreaToCursor(),this._signal("afterRender",e);return}if(e&this.CHANGE_SCROLL){this.$changedLines=null,e&this.CHANGE_TEXT||e&this.CHANGE_LINES?this.$textLayer.update(n):this.$textLayer.scrollLines(n),this.$showGutter&&(e&this.CHANGE_GUTTER||e&this.CHANGE_LINES?this.$gutterLayer.update(n):this.$gutterLayer.scrollLines(n)),this.$markerBack.update(n),this.$markerFront.update(n),this.$cursorLayer.update(n),this.$moveTextAreaToCursor(),this._signal("afterRender",e);return}e&this.CHANGE_TEXT?(this.$changedLines=null,this.$textLayer.update(n),this.$showGutter&&this.$gutterLayer.update(n)):e&this.CHANGE_LINES?(this.$updateLines()||e&this.CHANGE_GUTTER&&this.$showGutter)&&this.$gutterLayer.update(n):e&this.CHANGE_TEXT||e&this.CHANGE_GUTTER?this.$showGutter&&this.$gutterLayer.update(n):e&this.CHANGE_CURSOR&&this.$highlightGutterLine&&this.$gutterLayer.updateLineHighlight(n),e&this.CHANGE_CURSOR&&(this.$cursorLayer.update(n),this.$moveTextAreaToCursor()),e&(this.CHANGE_MARKER|this.CHANGE_MARKER_FRONT)&&this.$markerFront.update(n),e&(this.CHANGE_MARKER|this.CHANGE_MARKER_BACK)&&this.$markerBack.update(n),this._signal("afterRender",e)},this.$autosize=function(){var e=this.session.getScreenLength()*this.lineHeight,t=this.$maxLines*this.lineHeight,n=Math.min(t,Math.max((this.$minLines||1)*this.lineHeight,e))+this.scrollMargin.v+(this.$extraHeight||0);this.$horizScroll&&(n+=this.scrollBarH.getHeight()),this.$maxPixelHeight&&n>this.$maxPixelHeight&&(n=this.$maxPixelHeight);var r=n<=2*this.lineHeight,i=!r&&e>t;if(n!=this.desiredHeight||this.$size.height!=this.desiredHeight||i!=this.$vScroll){i!=this.$vScroll&&(this.$vScroll=i,this.scrollBarV.setVisible(i));var s=this.container.clientWidth;this.container.style.height=n+"px",this.$updateCachedSize(!0,this.$gutterWidth,s,n),this.desiredHeight=n,this._signal("autosize")}},this.$computeLayerConfig=function(){var e=this.session,t=this.$size,n=t.height<=2*this.lineHeight,r=this.session.getScreenLength(),i=r*this.lineHeight,s=this.$getLongestLine(),o=!n&&(this.$hScrollBarAlwaysVisible||t.scrollerWidth-s-2*this.$padding<0),u=this.$horizScroll!==o;u&&(this.$horizScroll=o,this.scrollBarH.setVisible(o));var a=this.$vScroll;this.$maxLines&&this.lineHeight>1&&this.$autosize();var f=t.scrollerHeight+this.lineHeight,l=!this.$maxLines&&this.$scrollPastEnd?(t.scrollerHeight-this.lineHeight)*this.$scrollPastEnd:0;i+=l;var c=this.scrollMargin;this.session.setScrollTop(Math.max(-c.top,Math.min(this.scrollTop,i-t.scrollerHeight+c.bottom))),this.session.setScrollLeft(Math.max(-c.left,Math.min(this.scrollLeft,s+2*this.$padding-t.scrollerWidth+c.right)));var h=!n&&(this.$vScrollBarAlwaysVisible||t.scrollerHeight-i+l<0||this.scrollTop>c.top),p=a!==h;p&&(this.$vScroll=h,this.scrollBarV.setVisible(h));var d=this.scrollTop%this.lineHeight,v=Math.ceil(f/this.lineHeight)-1,m=Math.max(0,Math.round((this.scrollTop-d)/this.lineHeight)),g=m+v,y,b,w=this.lineHeight;m=e.screenToDocumentRow(m,0);var E=e.getFoldLine(m);E&&(m=E.start.row),y=e.documentToScreenRow(m,0),b=e.getRowLength(m)*w,g=Math.min(e.screenToDocumentRow(g,0),e.getLength()-1),f=t.scrollerHeight+e.getRowLength(g)*w+b,d=this.scrollTop-y*w;var S=0;if(this.layerConfig.width!=s||u)S=this.CHANGE_H_SCROLL;if(u||p)S|=this.$updateCachedSize(!0,this.gutterWidth,t.width,t.height),this._signal("scrollbarVisibilityChanged"),p&&(s=this.$getLongestLine());return this.layerConfig={width:s,padding:this.$padding,firstRow:m,firstRowScreen:y,lastRow:g,lineHeight:w,characterWidth:this.characterWidth,minHeight:f,maxHeight:i,offset:d,gutterOffset:w?Math.max(0,Math.ceil((d+t.height-t.scrollerHeight)/w)):0,height:this.$size.scrollerHeight},this.session.$bidiHandler&&this.session.$bidiHandler.setContentWidth(s-this.$padding),S},this.$updateLines=function(){if(!this.$changedLines)return;var e=this.$changedLines.firstRow,t=this.$changedLines.lastRow;this.$changedLines=null;var n=this.layerConfig;if(e>n.lastRow+1)return;if(tthis.$textLayer.MAX_LINE_LENGTH&&(e=this.$textLayer.MAX_LINE_LENGTH+30),Math.max(this.$size.scrollerWidth-2*this.$padding,Math.round(e*this.characterWidth))},this.updateFrontMarkers=function(){this.$markerFront.setMarkers(this.session.getMarkers(!0)),this.$loop.schedule(this.CHANGE_MARKER_FRONT)},this.updateBackMarkers=function(){this.$markerBack.setMarkers(this.session.getMarkers()),this.$loop.schedule(this.CHANGE_MARKER_BACK)},this.addGutterDecoration=function(e,t){this.$gutterLayer.addGutterDecoration(e,t)},this.removeGutterDecoration=function(e,t){this.$gutterLayer.removeGutterDecoration(e,t)},this.updateBreakpoints=function(e){this.$loop.schedule(this.CHANGE_GUTTER)},this.setAnnotations=function(e){this.$gutterLayer.setAnnotations(e),this.$loop.schedule(this.CHANGE_GUTTER)},this.updateCursor=function(){this.$loop.schedule(this.CHANGE_CURSOR)},this.hideCursor=function(){this.$cursorLayer.hideCursor()},this.showCursor=function(){this.$cursorLayer.showCursor()},this.scrollSelectionIntoView=function(e,t,n){this.scrollCursorIntoView(e,n),this.scrollCursorIntoView(t,n)},this.scrollCursorIntoView=function(e,t,n){if(this.$size.scrollerHeight===0)return;var r=this.$cursorLayer.getPixelPosition(e),i=r.left,s=r.top,o=n&&n.top||0,u=n&&n.bottom||0,a=this.$scrollAnimation?this.session.getScrollTop():this.scrollTop;a+o>s?(t&&a+o>s+this.lineHeight&&(s-=t*this.$size.scrollerHeight),s===0&&(s=-this.scrollMargin.top),this.session.setScrollTop(s)):a+this.$size.scrollerHeight-ui?(i=1-this.scrollMargin.top)return!0;if(t>0&&this.session.getScrollTop()+this.$size.scrollerHeight-this.layerConfig.maxHeight<-1+this.scrollMargin.bottom)return!0;if(e<0&&this.session.getScrollLeft()>=1-this.scrollMargin.left)return!0;if(e>0&&this.session.getScrollLeft()+this.$size.scrollerWidth-this.layerConfig.width<-1+this.scrollMargin.right)return!0},this.pixelToScreenCoordinates=function(e,t){var n;if(this.$hasCssTransforms){n={top:0,left:0};var r=this.$fontMetrics.transformCoordinates([e,t]);e=r[1]-this.gutterWidth-this.margin.left,t=r[0]}else n=this.scroller.getBoundingClientRect();var i=e+this.scrollLeft-n.left-this.$padding,s=i/this.characterWidth,o=Math.floor((t+this.scrollTop-n.top)/this.lineHeight),u=this.$blockCursor?Math.floor(s):Math.round(s);return{row:o,column:u,side:s-u>0?1:-1,offsetX:i}},this.screenToTextCoordinates=function(e,t){var n;if(this.$hasCssTransforms){n={top:0,left:0};var r=this.$fontMetrics.transformCoordinates([e,t]);e=r[1]-this.gutterWidth-this.margin.left,t=r[0]}else n=this.scroller.getBoundingClientRect();var i=e+this.scrollLeft-n.left-this.$padding,s=i/this.characterWidth,o=this.$blockCursor?Math.floor(s):Math.round(s),u=Math.floor((t+this.scrollTop-n.top)/this.lineHeight);return this.session.screenToDocumentPosition(u,Math.max(o,0),i)},this.textToScreenCoordinates=function(e,t){var n=this.scroller.getBoundingClientRect(),r=this.session.documentToScreenPosition(e,t),i=this.$padding+(this.session.$bidiHandler.isBidiRow(r.row,e)?this.session.$bidiHandler.getPosLeft(r.column):Math.round(r.column*this.characterWidth)),s=r.row*this.lineHeight;return{pageX:n.left+i-this.scrollLeft,pageY:n.top+s-this.scrollTop}},this.visualizeFocus=function(){i.addCssClass(this.container,"ace_focus")},this.visualizeBlur=function(){i.removeCssClass(this.container,"ace_focus")},this.showComposition=function(e){this.$composition=e,e.cssText||(e.cssText=this.textarea.style.cssText),e.useTextareaForIME==undefined&&(e.useTextareaForIME=this.$useTextareaForIME),this.$useTextareaForIME?(i.addCssClass(this.textarea,"ace_composition"),this.textarea.style.cssText="",this.$moveTextAreaToCursor(),this.$cursorLayer.element.style.display="none"):e.markerId=this.session.addMarker(e.markerRange,"ace_composition_marker","text")},this.setCompositionText=function(e){var t=this.session.selection.cursor;this.addToken(e,"composition_placeholder",t.row,t.column),this.$moveTextAreaToCursor()},this.hideComposition=function(){if(!this.$composition)return;this.$composition.markerId&&this.session.removeMarker(this.$composition.markerId),i.removeCssClass(this.textarea,"ace_composition"),this.textarea.style.cssText=this.$composition.cssText;var e=this.session.selection.cursor;this.removeExtraToken(e.row,e.column),this.$composition=null,this.$cursorLayer.element.style.display=""},this.addToken=function(e,t,n,r){var i=this.session;i.bgTokenizer.lines[n]=null;var s={type:t,value:e},o=i.getTokens(n);if(r==null)o.push(s);else{var u=0;for(var a=0;a50&&e.length>this.$doc.getLength()>>1?this.call("setValue",[this.$doc.getValue()]):this.emit("change",{data:e})}}).call(f.prototype);var l=function(e,t,n){var r=null,i=!1,u=Object.create(s),a=[],l=new f({messageBuffer:a,terminate:function(){},postMessage:function(e){a.push(e);if(!r)return;i?setTimeout(c):c()}});l.setEmitSync=function(e){i=e};var c=function(){var e=a.shift();e.command?r[e.command].apply(r,e.args):e.event&&u._signal(e.event,e.data)};return u.postMessage=function(e){l.onMessage({data:e})},u.callback=function(e,t){this.postMessage({type:"call",id:t,data:e})},u.emit=function(e,t){this.postMessage({type:"event",name:e,data:t})},o.loadModule(["worker",t],function(e){r=new e[n](u);while(a.length)c()}),l};t.UIWorkerClient=l,t.WorkerClient=f,t.createWorker=a}),define("ace/placeholder",["require","exports","module","ace/range","ace/lib/event_emitter","ace/lib/oop"],function(e,t,n){"use strict";var r=e("./range").Range,i=e("./lib/event_emitter").EventEmitter,s=e("./lib/oop"),o=function(e,t,n,r,i,s){var o=this;this.length=t,this.session=e,this.doc=e.getDocument(),this.mainClass=i,this.othersClass=s,this.$onUpdate=this.onUpdate.bind(this),this.doc.on("change",this.$onUpdate),this.$others=r,this.$onCursorChange=function(){setTimeout(function(){o.onCursorChange()})},this.$pos=n;var u=e.getUndoManager().$undoStack||e.getUndoManager().$undostack||{length:-1};this.$undoStackDepth=u.length,this.setup(),e.selection.on("changeCursor",this.$onCursorChange)};(function(){s.implement(this,i),this.setup=function(){var e=this,t=this.doc,n=this.session;this.selectionBefore=n.selection.toJSON(),n.selection.inMultiSelectMode&&n.selection.toSingleRange(),this.pos=t.createAnchor(this.$pos.row,this.$pos.column);var i=this.pos;i.$insertRight=!0,i.detach(),i.markerId=n.addMarker(new r(i.row,i.column,i.row,i.column+this.length),this.mainClass,null,!1),this.others=[],this.$others.forEach(function(n){var r=t.createAnchor(n.row,n.column);r.$insertRight=!0,r.detach(),e.others.push(r)}),n.setUndoSelect(!1)},this.showOtherMarkers=function(){if(this.othersActive)return;var e=this.session,t=this;this.othersActive=!0,this.others.forEach(function(n){n.markerId=e.addMarker(new r(n.row,n.column,n.row,n.column+t.length),t.othersClass,null,!1)})},this.hideOtherMarkers=function(){if(!this.othersActive)return;this.othersActive=!1;for(var e=0;e=this.pos.column&&t.start.column<=this.pos.column+this.length+1,s=t.start.column-this.pos.column;this.updateAnchors(e),i&&(this.length+=n);if(i&&!this.session.$fromUndo)if(e.action==="insert")for(var o=this.others.length-1;o>=0;o--){var u=this.others[o],a={row:u.row,column:u.column+s};this.doc.insertMergedLines(a,e.lines)}else if(e.action==="remove")for(var o=this.others.length-1;o>=0;o--){var u=this.others[o],a={row:u.row,column:u.column+s};this.doc.remove(new r(a.row,a.column,a.row,a.column-n))}this.$updating=!1,this.updateMarkers()},this.updateAnchors=function(e){this.pos.onChange(e);for(var t=this.others.length;t--;)this.others[t].onChange(e);this.updateMarkers()},this.updateMarkers=function(){if(this.$updating)return;var e=this,t=this.session,n=function(n,i){t.removeMarker(n.markerId),n.markerId=t.addMarker(new r(n.row,n.column,n.row,n.column+e.length),i,null,!1)};n(this.pos,this.mainClass);for(var i=this.others.length;i--;)n(this.others[i],this.othersClass)},this.onCursorChange=function(e){if(this.$updating||!this.session)return;var t=this.session.selection.getCursor();t.row===this.pos.row&&t.column>=this.pos.column&&t.column<=this.pos.column+this.length?(this.showOtherMarkers(),this._emit("cursorEnter",e)):(this.hideOtherMarkers(),this._emit("cursorLeave",e))},this.detach=function(){this.session.removeMarker(this.pos&&this.pos.markerId),this.hideOtherMarkers(),this.doc.off("change",this.$onUpdate),this.session.selection.off("changeCursor",this.$onCursorChange),this.session.setUndoSelect(!0),this.session=null},this.cancel=function(){if(this.$undoStackDepth===-1)return;var e=this.session.getUndoManager(),t=(e.$undoStack||e.$undostack).length-this.$undoStackDepth;for(var n=0;n1?e.multiSelect.joinSelections():e.multiSelect.splitIntoLines()},bindKey:{win:"Ctrl-Alt-L",mac:"Ctrl-Alt-L"},readOnly:!0},{name:"splitSelectionIntoLines",description:"Split into lines",exec:function(e){e.multiSelect.splitIntoLines()},readOnly:!0},{name:"alignCursors",description:"Align cursors",exec:function(e){e.alignCursors()},bindKey:{win:"Ctrl-Alt-A",mac:"Ctrl-Alt-A"},scrollIntoView:"cursor"},{name:"findAll",description:"Find all",exec:function(e){e.findAll()},bindKey:{win:"Ctrl-Alt-K",mac:"Ctrl-Alt-G"},scrollIntoView:"cursor",readOnly:!0}],t.multiSelectCommands=[{name:"singleSelection",description:"Single selection",bindKey:"esc",exec:function(e){e.exitMultiSelectMode()},scrollIntoView:"cursor",readOnly:!0,isAvailable:function(e){return e&&e.inMultiSelectMode}}];var r=e("../keyboard/hash_handler").HashHandler;t.keyboardHandler=new r(t.multiSelectCommands)}),define("ace/multi_select",["require","exports","module","ace/range_list","ace/range","ace/selection","ace/mouse/multi_select_handler","ace/lib/event","ace/lib/lang","ace/commands/multi_select_commands","ace/search","ace/edit_session","ace/editor","ace/config"],function(e,t,n){function h(e,t,n){return c.$options.wrap=!0,c.$options.needle=t,c.$options.backwards=n==-1,c.find(e)}function v(e,t){return e.row==t.row&&e.column==t.column}function m(e){if(e.$multiselectOnSessionChange)return;e.$onAddRange=e.$onAddRange.bind(e),e.$onRemoveRange=e.$onRemoveRange.bind(e),e.$onMultiSelect=e.$onMultiSelect.bind(e),e.$onSingleSelect=e.$onSingleSelect.bind(e),e.$multiselectOnSessionChange=t.onSessionChange.bind(e),e.$checkMultiselectChange=e.$checkMultiselectChange.bind(e),e.$multiselectOnSessionChange(e),e.on("changeSession",e.$multiselectOnSessionChange),e.on("mousedown",o),e.commands.addCommands(f.defaultCommands),g(e)}function g(e){function r(t){n&&(e.renderer.setMouseCursor(""),n=!1)}if(!e.textInput)return;var t=e.textInput.getElement(),n=!1;u.addListener(t,"keydown",function(t){var i=t.keyCode==18&&!(t.ctrlKey||t.shiftKey||t.metaKey);e.$blockSelectEnabled&&i?n||(e.renderer.setMouseCursor("crosshair"),n=!0):n&&r()},e),u.addListener(t,"keyup",r,e),u.addListener(t,"blur",r,e)}var r=e("./range_list").RangeList,i=e("./range").Range,s=e("./selection").Selection,o=e("./mouse/multi_select_handler").onMouseDown,u=e("./lib/event"),a=e("./lib/lang"),f=e("./commands/multi_select_commands");t.commands=f.defaultCommands.concat(f.multiSelectCommands);var l=e("./search").Search,c=new l,p=e("./edit_session").EditSession;(function(){this.getSelectionMarkers=function(){return this.$selectionMarkers}}).call(p.prototype),function(){this.ranges=null,this.rangeList=null,this.addRange=function(e,t){if(!e)return;if(!this.inMultiSelectMode&&this.rangeCount===0){var n=this.toOrientedRange();this.rangeList.add(n),this.rangeList.add(e);if(this.rangeList.ranges.length!=2)return this.rangeList.removeAll(),t||this.fromOrientedRange(e);this.rangeList.removeAll(),this.rangeList.add(n),this.$onAddRange(n)}e.cursor||(e.cursor=e.end);var r=this.rangeList.add(e);return this.$onAddRange(e),r.length&&this.$onRemoveRange(r),this.rangeCount>1&&!this.inMultiSelectMode&&(this._signal("multiSelect"),this.inMultiSelectMode=!0,this.session.$undoSelect=!1,this.rangeList.attach(this.session)),t||this.fromOrientedRange(e)},this.toSingleRange=function(e){e=e||this.ranges[0];var t=this.rangeList.removeAll();t.length&&this.$onRemoveRange(t),e&&this.fromOrientedRange(e)},this.substractPoint=function(e){var t=this.rangeList.substractPoint(e);if(t)return this.$onRemoveRange(t),t[0]},this.mergeOverlappingRanges=function(){var e=this.rangeList.merge();e.length&&this.$onRemoveRange(e)},this.$onAddRange=function(e){this.rangeCount=this.rangeList.ranges.length,this.ranges.unshift(e),this._signal("addRange",{range:e})},this.$onRemoveRange=function(e){this.rangeCount=this.rangeList.ranges.length;if(this.rangeCount==1&&this.inMultiSelectMode){var t=this.rangeList.ranges.pop();e.push(t),this.rangeCount=0}for(var n=e.length;n--;){var r=this.ranges.indexOf(e[n]);this.ranges.splice(r,1)}this._signal("removeRange",{ranges:e}),this.rangeCount===0&&this.inMultiSelectMode&&(this.inMultiSelectMode=!1,this._signal("singleSelect"),this.session.$undoSelect=!0,this.rangeList.detach(this.session)),t=t||this.ranges[0],t&&!t.isEqual(this.getRange())&&this.fromOrientedRange(t)},this.$initRangeList=function(){if(this.rangeList)return;this.rangeList=new r,this.ranges=[],this.rangeCount=0},this.getAllRanges=function(){return this.rangeCount?this.rangeList.ranges.concat():[this.getRange()]},this.splitIntoLines=function(){var e=this.ranges.length?this.ranges:[this.getRange()],t=[];for(var n=0;n1){var e=this.rangeList.ranges,t=e[e.length-1],n=i.fromPoints(e[0].start,t.end);this.toSingleRange(),this.setSelectionRange(n,t.cursor==t.start)}else{var r=this.session.documentToScreenPosition(this.cursor),s=this.session.documentToScreenPosition(this.anchor),o=this.rectangularRangeBlock(r,s);o.forEach(this.addRange,this)}},this.rectangularRangeBlock=function(e,t,n){var r=[],s=e.column0)g--;if(g>0){var y=0;while(r[y].isEmpty())y++}for(var b=g;b>=y;b--)r[b].isEmpty()&&r.splice(b,1)}return r}}.call(s.prototype);var d=e("./editor").Editor;(function(){this.updateSelectionMarkers=function(){this.renderer.updateCursor(),this.renderer.updateBackMarkers()},this.addSelectionMarker=function(e){e.cursor||(e.cursor=e.end);var t=this.getSelectionStyle();return e.marker=this.session.addMarker(e,"ace_selection",t),this.session.$selectionMarkers.push(e),this.session.selectionMarkerCount=this.session.$selectionMarkers.length,e},this.removeSelectionMarker=function(e){if(!e.marker)return;this.session.removeMarker(e.marker);var t=this.session.$selectionMarkers.indexOf(e);t!=-1&&this.session.$selectionMarkers.splice(t,1),this.session.selectionMarkerCount=this.session.$selectionMarkers.length},this.removeSelectionMarkers=function(e){var t=this.session.$selectionMarkers;for(var n=e.length;n--;){var r=e[n];if(!r.marker)continue;this.session.removeMarker(r.marker);var i=t.indexOf(r);i!=-1&&t.splice(i,1)}this.session.selectionMarkerCount=t.length},this.$onAddRange=function(e){this.addSelectionMarker(e.range),this.renderer.updateCursor(),this.renderer.updateBackMarkers()},this.$onRemoveRange=function(e){this.removeSelectionMarkers(e.ranges),this.renderer.updateCursor(),this.renderer.updateBackMarkers()},this.$onMultiSelect=function(e){if(this.inMultiSelectMode)return;this.inMultiSelectMode=!0,this.setStyle("ace_multiselect"),this.keyBinding.addKeyboardHandler(f.keyboardHandler),this.commands.setDefaultHandler("exec",this.$onMultiSelectExec),this.renderer.updateCursor(),this.renderer.updateBackMarkers()},this.$onSingleSelect=function(e){if(this.session.multiSelect.inVirtualMode)return;this.inMultiSelectMode=!1,this.unsetStyle("ace_multiselect"),this.keyBinding.removeKeyboardHandler(f.keyboardHandler),this.commands.removeDefaultHandler("exec",this.$onMultiSelectExec),this.renderer.updateCursor(),this.renderer.updateBackMarkers(),this._emit("changeSelection")},this.$onMultiSelectExec=function(e){var t=e.command,n=e.editor;if(!n.multiSelect)return;if(!t.multiSelectAction){var r=t.exec(n,e.args||{});n.multiSelect.addRange(n.multiSelect.toOrientedRange()),n.multiSelect.mergeOverlappingRanges()}else t.multiSelectAction=="forEach"?r=n.forEachSelection(t,e.args):t.multiSelectAction=="forEachLine"?r=n.forEachSelection(t,e.args,!0):t.multiSelectAction=="single"?(n.exitMultiSelectMode(),r=t.exec(n,e.args||{})):r=t.multiSelectAction(n,e.args||{});return r},this.forEachSelection=function(e,t,n){if(this.inVirtualSelectionMode)return;var r=n&&n.keepOrder,i=n==1||n&&n.$byLines,o=this.session,u=this.selection,a=u.rangeList,f=(r?u:a).ranges,l;if(!f.length)return e.exec?e.exec(this,t||{}):e(this,t||{});var c=u._eventRegistry;u._eventRegistry={};var h=new s(o);this.inVirtualSelectionMode=!0;for(var p=f.length;p--;){if(i)while(p>0&&f[p].start.row==f[p-1].end.row)p--;h.fromOrientedRange(f[p]),h.index=p,this.selection=o.selection=h;var d=e.exec?e.exec(this,t||{}):e(this,t||{});!l&&d!==undefined&&(l=d),h.toOrientedRange(f[p])}h.detach(),this.selection=o.selection=u,this.inVirtualSelectionMode=!1,u._eventRegistry=c,u.mergeOverlappingRanges(),u.ranges[0]&&u.fromOrientedRange(u.ranges[0]);var v=this.renderer.$scrollAnimation;return this.onCursorChange(),this.onSelectionChange(),v&&v.from==v.to&&this.renderer.animateScrolling(v.from),l},this.exitMultiSelectMode=function(){if(!this.inMultiSelectMode||this.inVirtualSelectionMode)return;this.multiSelect.toSingleRange()},this.getSelectedText=function(){var e="";if(this.inMultiSelectMode&&!this.inVirtualSelectionMode){var t=this.multiSelect.rangeList.ranges,n=[];for(var r=0;r0);u<0&&(u=0),f>=c&&(f=c-1)}var p=this.session.removeFullLines(u,f);p=this.$reAlignText(p,l),this.session.insert({row:u,column:0},p.join("\n")+"\n"),l||(o.start.column=0,o.end.column=p[p.length-1].length),this.selection.setRange(o)}else{s.forEach(function(e){t.substractPoint(e.cursor)});var d=0,v=Infinity,m=n.map(function(t){var n=t.cursor,r=e.getLine(n.row),i=r.substr(n.column).search(/\S/g);return i==-1&&(i=0),n.column>d&&(d=n.column),io?e.insert(r,a.stringRepeat(" ",s-o)):e.remove(new i(r.row,r.column,r.row,r.column-s+o)),t.start.column=t.end.column=d,t.start.row=t.end.row=r.row,t.cursor=t.end}),t.fromOrientedRange(n[0]),this.renderer.updateCursor(),this.renderer.updateBackMarkers()}},this.$reAlignText=function(e,t){function u(e){return a.stringRepeat(" ",e)}function f(e){return e[2]?u(i)+e[2]+u(s-e[2].length+o)+e[4].replace(/^([=:])\s+/,"$1 "):e[0]}function l(e){return e[2]?u(i+s-e[2].length)+e[2]+u(o)+e[4].replace(/^([=:])\s+/,"$1 "):e[0]}function c(e){return e[2]?u(i)+e[2]+u(o)+e[4].replace(/^([=:])\s+/,"$1 "):e[0]}var n=!0,r=!0,i,s,o;return e.map(function(e){var t=e.match(/(\s*)(.*?)(\s*)([=:].*)/);return t?i==null?(i=t[1].length,s=t[2].length,o=t[3].length,t):(i+s+o!=t[1].length+t[2].length+t[3].length&&(r=!1),i!=t[1].length&&(n=!1),i>t[1].length&&(i=t[1].length),st[3].length&&(o=t[3].length),t):[e]}).map(t?f:n?r?l:f:c)}}).call(d.prototype),t.onSessionChange=function(e){var t=e.session;t&&!t.multiSelect&&(t.$selectionMarkers=[],t.selection.$initRangeList(),t.multiSelect=t.selection),this.multiSelect=t&&t.multiSelect;var n=e.oldSession;n&&(n.multiSelect.off("addRange",this.$onAddRange),n.multiSelect.off("removeRange",this.$onRemoveRange),n.multiSelect.off("multiSelect",this.$onMultiSelect),n.multiSelect.off("singleSelect",this.$onSingleSelect),n.multiSelect.lead.off("change",this.$checkMultiselectChange),n.multiSelect.anchor.off("change",this.$checkMultiselectChange)),t&&(t.multiSelect.on("addRange",this.$onAddRange),t.multiSelect.on("removeRange",this.$onRemoveRange),t.multiSelect.on("multiSelect",this.$onMultiSelect),t.multiSelect.on("singleSelect",this.$onSingleSelect),t.multiSelect.lead.on("change",this.$checkMultiselectChange),t.multiSelect.anchor.on("change",this.$checkMultiselectChange)),t&&this.inMultiSelectMode!=t.selection.inMultiSelectMode&&(t.selection.inMultiSelectMode?this.$onMultiSelect():this.$onSingleSelect())},t.MultiSelect=m,e("./config").defineOptions(d.prototype,"editor",{enableMultiselect:{set:function(e){m(this),e?(this.on("changeSession",this.$multiselectOnSessionChange),this.on("mousedown",o)):(this.off("changeSession",this.$multiselectOnSessionChange),this.off("mousedown",o))},value:!0},enableBlockSelect:{set:function(e){this.$blockSelectEnabled=e},value:!0}})}),define("ace/mode/folding/fold_mode",["require","exports","module","ace/range"],function(e,t,n){"use strict";var r=e("../../range").Range,i=t.FoldMode=function(){};(function(){this.foldingStartMarker=null,this.foldingStopMarker=null,this.getFoldWidget=function(e,t,n){var r=e.getLine(n);return this.foldingStartMarker.test(r)?"start":t=="markbeginend"&&this.foldingStopMarker&&this.foldingStopMarker.test(r)?"end":""},this.getFoldWidgetRange=function(e,t,n){return null},this.indentationBlock=function(e,t,n){var i=/\S/,s=e.getLine(t),o=s.search(i);if(o==-1)return;var u=n||s.length,a=e.getLength(),f=t,l=t;while(++tf){var p=e.getLine(l).length;return new r(f,u,l,p)}},this.openingBracketBlock=function(e,t,n,i,s){var o={row:n,column:i+1},u=e.$findClosingBracket(t,o,s);if(!u)return;var a=e.foldWidgets[u.row];return a==null&&(a=e.getFoldWidget(u.row)),a=="start"&&u.row>o.row&&(u.row--,u.column=e.getLine(u.row).length),r.fromPoints(o,u)},this.closingBracketBlock=function(e,t,n,i,s){var o={row:n,column:i},u=e.$findOpeningBracket(t,o);if(!u)return;return u.column++,o.column--,r.fromPoints(u,o)}}).call(i.prototype)}),define("ace/theme/textmate",["require","exports","module","ace/lib/dom"],function(e,t,n){"use strict";t.isDark=!1,t.cssClass="ace-tm",t.cssText='.ace-tm .ace_gutter {background: #f0f0f0;color: #333;}.ace-tm .ace_print-margin {width: 1px;background: #e8e8e8;}.ace-tm .ace_fold {background-color: #6B72E6;}.ace-tm {background-color: #FFFFFF;color: black;}.ace-tm .ace_cursor {color: black;}.ace-tm .ace_invisible {color: rgb(191, 191, 191);}.ace-tm .ace_storage,.ace-tm .ace_keyword {color: blue;}.ace-tm .ace_constant {color: rgb(197, 6, 11);}.ace-tm .ace_constant.ace_buildin {color: rgb(88, 72, 246);}.ace-tm .ace_constant.ace_language {color: rgb(88, 92, 246);}.ace-tm .ace_constant.ace_library {color: rgb(6, 150, 14);}.ace-tm .ace_invalid {background-color: rgba(255, 0, 0, 0.1);color: red;}.ace-tm .ace_support.ace_function {color: rgb(60, 76, 114);}.ace-tm .ace_support.ace_constant {color: rgb(6, 150, 14);}.ace-tm .ace_support.ace_type,.ace-tm .ace_support.ace_class {color: rgb(109, 121, 222);}.ace-tm .ace_keyword.ace_operator {color: rgb(104, 118, 135);}.ace-tm .ace_string {color: rgb(3, 106, 7);}.ace-tm .ace_comment {color: rgb(76, 136, 107);}.ace-tm .ace_comment.ace_doc {color: rgb(0, 102, 255);}.ace-tm .ace_comment.ace_doc.ace_tag {color: rgb(128, 159, 191);}.ace-tm .ace_constant.ace_numeric {color: rgb(0, 0, 205);}.ace-tm .ace_variable {color: rgb(49, 132, 149);}.ace-tm .ace_xml-pe {color: rgb(104, 104, 91);}.ace-tm .ace_entity.ace_name.ace_function {color: #0000A2;}.ace-tm .ace_heading {color: rgb(12, 7, 255);}.ace-tm .ace_list {color:rgb(185, 6, 144);}.ace-tm .ace_meta.ace_tag {color:rgb(0, 22, 142);}.ace-tm .ace_string.ace_regex {color: rgb(255, 0, 0)}.ace-tm .ace_marker-layer .ace_selection {background: rgb(181, 213, 255);}.ace-tm.ace_multiselect .ace_selection.ace_start {box-shadow: 0 0 3px 0px white;}.ace-tm .ace_marker-layer .ace_step {background: rgb(252, 255, 0);}.ace-tm .ace_marker-layer .ace_stack {background: rgb(164, 229, 101);}.ace-tm .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid rgb(192, 192, 192);}.ace-tm .ace_marker-layer .ace_active-line {background: rgba(0, 0, 0, 0.07);}.ace-tm .ace_gutter-active-line {background-color : #dcdcdc;}.ace-tm .ace_marker-layer .ace_selected-word {background: rgb(250, 250, 255);border: 1px solid rgb(200, 200, 250);}.ace-tm .ace_indent-guide {background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==") right repeat-y;}',t.$id="ace/theme/textmate";var r=e("../lib/dom");r.importCssString(t.cssText,t.cssClass,!1)}),define("ace/line_widgets",["require","exports","module","ace/lib/dom"],function(e,t,n){"use strict";function i(e){this.session=e,this.session.widgetManager=this,this.session.getRowLength=this.getRowLength,this.session.$getWidgetScreenLength=this.$getWidgetScreenLength,this.updateOnChange=this.updateOnChange.bind(this),this.renderWidgets=this.renderWidgets.bind(this),this.measureWidgets=this.measureWidgets.bind(this),this.session._changedWidgets=[],this.$onChangeEditor=this.$onChangeEditor.bind(this),this.session.on("change",this.updateOnChange),this.session.on("changeFold",this.updateOnFold),this.session.on("changeEditor",this.$onChangeEditor)}var r=e("./lib/dom");(function(){this.getRowLength=function(e){var t;return this.lineWidgets?t=this.lineWidgets[e]&&this.lineWidgets[e].rowCount||0:t=0,!this.$useWrapMode||!this.$wrapData[e]?1+t:this.$wrapData[e].length+1+t},this.$getWidgetScreenLength=function(){var e=0;return this.lineWidgets.forEach(function(t){t&&t.rowCount&&!t.hidden&&(e+=t.rowCount)}),e},this.$onChangeEditor=function(e){this.attach(e.editor)},this.attach=function(e){e&&e.widgetManager&&e.widgetManager!=this&&e.widgetManager.detach();if(this.editor==e)return;this.detach(),this.editor=e,e&&(e.widgetManager=this,e.renderer.on("beforeRender",this.measureWidgets),e.renderer.on("afterRender",this.renderWidgets))},this.detach=function(e){var t=this.editor;if(!t)return;this.editor=null,t.widgetManager=null,t.renderer.off("beforeRender",this.measureWidgets),t.renderer.off("afterRender",this.renderWidgets);var n=this.session.lineWidgets;n&&n.forEach(function(e){e&&e.el&&e.el.parentNode&&(e._inDocument=!1,e.el.parentNode.removeChild(e.el))})},this.updateOnFold=function(e,t){var n=t.lineWidgets;if(!n||!e.action)return;var r=e.data,i=r.start.row,s=r.end.row,o=e.action=="add";for(var u=i+1;ut[n].column&&n++,s.unshift(n,0),t.splice.apply(t,s),this.$updateRows()}},this.$updateRows=function(){var e=this.session.lineWidgets;if(!e)return;var t=!0;e.forEach(function(e,n){if(e){t=!1,e.row=n;while(e.$oldWidget)e.$oldWidget.row=n,e=e.$oldWidget}}),t&&(this.session.lineWidgets=null)},this.$registerLineWidget=function(e){this.session.lineWidgets||(this.session.lineWidgets=new Array(this.session.getLength()));var t=this.session.lineWidgets[e.row];return t&&(e.$oldWidget=t,t.el&&t.el.parentNode&&(t.el.parentNode.removeChild(t.el),t._inDocument=!1)),this.session.lineWidgets[e.row]=e,e},this.addLineWidget=function(e){this.$registerLineWidget(e),e.session=this.session;if(!this.editor)return e;var t=this.editor.renderer;e.html&&!e.el&&(e.el=r.createElement("div"),e.el.innerHTML=e.html),e.el&&(r.addCssClass(e.el,"ace_lineWidgetContainer"),e.el.style.position="absolute",e.el.style.zIndex=5,t.container.appendChild(e.el),e._inDocument=!0,e.coverGutter||(e.el.style.zIndex=3),e.pixelHeight==null&&(e.pixelHeight=e.el.offsetHeight)),e.rowCount==null&&(e.rowCount=e.pixelHeight/t.layerConfig.lineHeight);var n=this.session.getFoldAt(e.row,0);e.$fold=n;if(n){var i=this.session.lineWidgets;e.row==n.end.row&&!i[n.start.row]?i[n.start.row]=e:e.hidden=!0}return this.session._emit("changeFold",{data:{start:{row:e.row}}}),this.$updateRows(),this.renderWidgets(null,t),this.onWidgetChanged(e),e},this.removeLineWidget=function(e){e._inDocument=!1,e.session=null,e.el&&e.el.parentNode&&e.el.parentNode.removeChild(e.el);if(e.editor&&e.editor.destroy)try{e.editor.destroy()}catch(t){}if(this.session.lineWidgets){var n=this.session.lineWidgets[e.row];if(n==e)this.session.lineWidgets[e.row]=e.$oldWidget,e.$oldWidget&&this.onWidgetChanged(e.$oldWidget);else while(n){if(n.$oldWidget==e){n.$oldWidget=e.$oldWidget;break}n=n.$oldWidget}}this.session._emit("changeFold",{data:{start:{row:e.row}}}),this.$updateRows()},this.getWidgetsAtRow=function(e){var t=this.session.lineWidgets,n=t&&t[e],r=[];while(n)r.push(n),n=n.$oldWidget;return r},this.onWidgetChanged=function(e){this.session._changedWidgets.push(e),this.editor&&this.editor.renderer.updateFull()},this.measureWidgets=function(e,t){var n=this.session._changedWidgets,r=t.layerConfig;if(!n||!n.length)return;var i=Infinity;for(var s=0;s0&&!r[i])i--;this.firstRow=n.firstRow,this.lastRow=n.lastRow,t.$cursorLayer.config=n;for(var o=i;o<=s;o++){var u=r[o];if(!u||!u.el)continue;if(u.hidden){u.el.style.top=-100-(u.pixelHeight||0)+"px";continue}u._inDocument||(u._inDocument=!0,t.container.appendChild(u.el));var a=t.$cursorLayer.getPixelPosition({row:o,column:0},!0).top;u.coverLine||(a+=n.lineHeight*this.session.getRowLineCount(u.row)),u.el.style.top=a-n.offset+"px";var f=u.coverGutter?0:t.gutterWidth;u.fixedWidth||(f-=t.scrollLeft),u.el.style.left=f+"px",u.fullWidth&&u.screenWidth&&(u.el.style.minWidth=n.width+2*n.padding+"px"),u.fixedWidth?u.el.style.right=t.scrollBar.getWidth()+"px":u.el.style.right=""}}}).call(i.prototype),t.LineWidgets=i}),define("ace/ext/error_marker",["require","exports","module","ace/line_widgets","ace/lib/dom","ace/range"],function(e,t,n){"use strict";function o(e,t,n){var r=0,i=e.length-1;while(r<=i){var s=r+i>>1,o=n(t,e[s]);if(o>0)r=s+1;else{if(!(o<0))return s;i=s-1}}return-(r+1)}function u(e,t,n){var r=e.getAnnotations().sort(s.comparePoints);if(!r.length)return;var i=o(r,{row:t,column:-1},s.comparePoints);i<0&&(i=-i-1),i>=r.length?i=n>0?0:r.length-1:i===0&&n<0&&(i=r.length-1);var u=r[i];if(!u||!n)return;if(u.row===t){do u=r[i+=n];while(u&&u.row===t);if(!u)return r.slice()}var a=[];t=u.row;do a[n<0?"unshift":"push"](u),u=r[i+=n];while(u&&u.row==t);return a.length&&a}var r=e("../line_widgets").LineWidgets,i=e("../lib/dom"),s=e("../range").Range;t.showErrorMarker=function(e,t){var n=e.session;n.widgetManager||(n.widgetManager=new r(n),n.widgetManager.attach(e));var s=e.getCursorPosition(),o=s.row,a=n.widgetManager.getWidgetsAtRow(o).filter(function(e){return e.type=="errorMarker"})[0];a?a.destroy():o-=t;var f=u(n,o,t),l;if(f){var c=f[0];s.column=(c.pos&&typeof c.column!="number"?c.pos.sc:c.column)||0,s.row=c.row,l=e.renderer.$gutterLayer.$annotations[s.row]}else{if(a)return;l={text:["Looks good!"],className:"ace_ok"}}e.session.unfold(s.row),e.selection.moveToPosition(s);var h={row:s.row,fixedWidth:!0,coverGutter:!0,el:i.createElement("div"),type:"errorMarker"},p=h.el.appendChild(i.createElement("div")),d=h.el.appendChild(i.createElement("div"));d.className="error_widget_arrow "+l.className;var v=e.renderer.$cursorLayer.getPixelPosition(s).left;d.style.left=v+e.renderer.gutterWidth-5+"px",h.el.className="error_widget_wrapper",p.className="error_widget "+l.className,p.innerHTML=l.text.join("
"),p.appendChild(i.createElement("div"));var m=function(e,t,n){if(t===0&&(n==="esc"||n==="return"))return h.destroy(),{command:"null"}};h.destroy=function(){if(e.$mouseHandler.isMousePressed)return;e.keyBinding.removeKeyboardHandler(m),n.widgetManager.removeLineWidget(h),e.off("changeSelection",h.destroy),e.off("changeSession",h.destroy),e.off("mouseup",h.destroy),e.off("change",h.destroy)},e.keyBinding.addKeyboardHandler(m),e.on("changeSelection",h.destroy),e.on("changeSession",h.destroy),e.on("mouseup",h.destroy),e.on("change",h.destroy),e.session.widgetManager.addLineWidget(h),h.el.onmousedown=e.focus.bind(e),e.renderer.scrollCursorIntoView(null,.5,{bottom:h.el.offsetHeight})},i.importCssString(" .error_widget_wrapper { background: inherit; color: inherit; border:none } .error_widget { border-top: solid 2px; border-bottom: solid 2px; margin: 5px 0; padding: 10px 40px; white-space: pre-wrap; } .error_widget.ace_error, .error_widget_arrow.ace_error{ border-color: #ff5a5a } .error_widget.ace_warning, .error_widget_arrow.ace_warning{ border-color: #F1D817 } .error_widget.ace_info, .error_widget_arrow.ace_info{ border-color: #5a5a5a } .error_widget.ace_ok, .error_widget_arrow.ace_ok{ border-color: #5aaa5a } .error_widget_arrow { position: absolute; border: solid 5px; border-top-color: transparent!important; border-right-color: transparent!important; border-left-color: transparent!important; top: -5px; }","error_marker.css",!1)}),define("ace/ace",["require","exports","module","ace/lib/fixoldbrowsers","ace/lib/dom","ace/lib/event","ace/range","ace/editor","ace/edit_session","ace/undomanager","ace/virtual_renderer","ace/worker/worker_client","ace/keyboard/hash_handler","ace/placeholder","ace/multi_select","ace/mode/folding/fold_mode","ace/theme/textmate","ace/ext/error_marker","ace/config"],function(e,t,n){"use strict";e("./lib/fixoldbrowsers");var r=e("./lib/dom"),i=e("./lib/event"),s=e("./range").Range,o=e("./editor").Editor,u=e("./edit_session").EditSession,a=e("./undomanager").UndoManager,f=e("./virtual_renderer").VirtualRenderer;e("./worker/worker_client"),e("./keyboard/hash_handler"),e("./placeholder"),e("./multi_select"),e("./mode/folding/fold_mode"),e("./theme/textmate"),e("./ext/error_marker"),t.config=e("./config"),t.require=e,typeof define=="function"&&(t.define=define),t.edit=function(e,n){if(typeof e=="string"){var s=e;e=document.getElementById(s);if(!e)throw new Error("ace.edit can't find div #"+s)}if(e&&e.env&&e.env.editor instanceof o)return e.env.editor;var u="";if(e&&/input|textarea/i.test(e.tagName)){var a=e;u=a.value,e=r.createElement("pre"),a.parentNode.replaceChild(e,a)}else e&&(u=e.textContent,e.innerHTML="");var l=t.createEditSession(u),c=new o(new f(e),l,n),h={document:l,editor:c,onResize:c.resize.bind(c,null)};return a&&(h.textarea=a),i.addListener(window,"resize",h.onResize),c.on("destroy",function(){i.removeListener(window,"resize",h.onResize),h.editor.container.env=null}),c.container.env=c.env=h,c},t.createEditSession=function(e,t){var n=new u(e,t);return n.setUndoManager(new a),n},t.Range=s,t.Editor=o,t.EditSession=u,t.UndoManager=a,t.VirtualRenderer=f,t.version=t.config.version}); (function() { + window.require(["ace/ace"], function(a) { + if (a) { + a.config.init(true); + a.define = window.define; + } + if (!window.ace) + window.ace = a; + for (var key in a) if (a.hasOwnProperty(key)) + window.ace[key] = a[key]; + window.ace["default"] = window.ace; + if (typeof module == "object" && typeof exports == "object" && module) { + module.exports = window.ace; + } + }); + })(); + \ No newline at end of file diff --git a/apps/block_scout_web/assets/js/lib/ace/src-min/mode-csharp.js b/apps/block_scout_web/assets/js/lib/ace/src-min/mode-csharp.js new file mode 100644 index 000000000000..9d59417e3175 --- /dev/null +++ b/apps/block_scout_web/assets/js/lib/ace/src-min/mode-csharp.js @@ -0,0 +1,8 @@ +/* eslint-disable */define("ace/mode/doc_comment_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){this.$rules={start:[{token:"comment.doc.tag",regex:"@[\\w\\d_]+"},s.getTagRule(),{defaultToken:"comment.doc",caseInsensitive:!0}]}};r.inherits(s,i),s.getTagRule=function(e){return{token:"comment.doc.tag.storage.type",regex:"\\b(?:TODO|FIXME|XXX|HACK)\\b"}},s.getStartRule=function(e){return{token:"comment.doc",regex:"\\/\\*(?=\\*)",next:e}},s.getEndRule=function(e){return{token:"comment.doc",regex:"\\*\\/",next:e}},t.DocCommentHighlightRules=s}),define("ace/mode/csharp_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/doc_comment_highlight_rules","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./doc_comment_highlight_rules").DocCommentHighlightRules,s=e("./text_highlight_rules").TextHighlightRules,o=function(){var e=this.createKeywordMapper({"variable.language":"this",keyword:"abstract|async|await|event|new|struct|as|explicit|null|switch|base|extern|object|this|bool|false|operator|throw|break|finally|out|true|byte|fixed|override|try|case|float|params|typeof|catch|for|private|uint|char|foreach|protected|ulong|checked|goto|public|unchecked|class|if|readonly|unsafe|const|implicit|ref|ushort|continue|in|return|using|decimal|int|sbyte|virtual|default|interface|sealed|volatile|delegate|internal|partial|short|void|do|is|sizeof|while|double|lock|stackalloc|else|long|static|enum|namespace|string|var|dynamic","constant.language":"null|true|false"},"identifier");this.$rules={start:[{token:"comment",regex:"\\/\\/.*$"},i.getStartRule("doc-start"),{token:"comment",regex:"\\/\\*",next:"comment"},{token:"string",regex:/'(?:.|\\(:?u[\da-fA-F]+|x[\da-fA-F]+|[tbrf'"n]))?'/},{token:"string",start:'"',end:'"|$',next:[{token:"constant.language.escape",regex:/\\(:?u[\da-fA-F]+|x[\da-fA-F]+|[tbrf'"n])/},{token:"invalid",regex:/\\./}]},{token:"string",start:'@"',end:'"',next:[{token:"constant.language.escape",regex:'""'}]},{token:"string",start:/\$"/,end:'"|$',next:[{token:"constant.language.escape",regex:/\\(:?$)|{{/},{token:"constant.language.escape",regex:/\\(:?u[\da-fA-F]+|x[\da-fA-F]+|[tbrf'"n])/},{token:"invalid",regex:/\\./}]},{token:"constant.numeric",regex:"0[xX][0-9a-fA-F]+\\b"},{token:"constant.numeric",regex:"[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"},{token:"constant.language.boolean",regex:"(?:true|false)\\b"},{token:e,regex:"[a-zA-Z_$][a-zA-Z0-9_$]*\\b"},{token:"keyword.operator",regex:"!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\b(?:in|instanceof|new|delete|typeof|void)"},{token:"keyword",regex:"^\\s*#(if|else|elif|endif|define|undef|warning|error|line|region|endregion|pragma)"},{token:"punctuation.operator",regex:"\\?|\\:|\\,|\\;|\\."},{token:"paren.lparen",regex:"[[({]"},{token:"paren.rparen",regex:"[\\])}]"},{token:"text",regex:"\\s+"}],comment:[{token:"comment",regex:"\\*\\/",next:"start"},{defaultToken:"comment"}]},this.embedRules(i,"doc-",[i.getEndRule("start")]),this.normalizeRules()};r.inherits(o,s),t.CSharpHighlightRules=o}),define("ace/mode/matching_brace_outdent",["require","exports","module","ace/range"],function(e,t,n){"use strict";var r=e("../range").Range,i=function(){};(function(){this.checkOutdent=function(e,t){return/^\s+$/.test(e)?/^\s*\}/.test(t):!1},this.autoOutdent=function(e,t){var n=e.getLine(t),i=n.match(/^(\s*\})/);if(!i)return 0;var s=i[1].length,o=e.findMatchingBracket({row:t,column:s});if(!o||o.row==t)return 0;var u=this.$getIndent(e.getLine(o.row));e.replace(new r(t,0,t,s-1),u)},this.$getIndent=function(e){return e.match(/^\s*/)[0]}}).call(i.prototype),t.MatchingBraceOutdent=i}),define("ace/mode/folding/cstyle",["require","exports","module","ace/lib/oop","ace/range","ace/mode/folding/fold_mode"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("../../range").Range,s=e("./fold_mode").FoldMode,o=t.FoldMode=function(e){e&&(this.foldingStartMarker=new RegExp(this.foldingStartMarker.source.replace(/\|[^|]*?$/,"|"+e.start)),this.foldingStopMarker=new RegExp(this.foldingStopMarker.source.replace(/\|[^|]*?$/,"|"+e.end)))};r.inherits(o,s),function(){this.foldingStartMarker=/([\{\[\(])[^\}\]\)]*$|^\s*(\/\*)/,this.foldingStopMarker=/^[^\[\{\(]*([\}\]\)])|^[\s\*]*(\*\/)/,this.singleLineBlockCommentRe=/^\s*(\/\*).*\*\/\s*$/,this.tripleStarBlockCommentRe=/^\s*(\/\*\*\*).*\*\/\s*$/,this.startRegionRe=/^\s*(\/\*|\/\/)#?region\b/,this._getFoldWidgetBase=this.getFoldWidget,this.getFoldWidget=function(e,t,n){var r=e.getLine(n);if(this.singleLineBlockCommentRe.test(r)&&!this.startRegionRe.test(r)&&!this.tripleStarBlockCommentRe.test(r))return"";var i=this._getFoldWidgetBase(e,t,n);return!i&&this.startRegionRe.test(r)?"start":i},this.getFoldWidgetRange=function(e,t,n,r){var i=e.getLine(n);if(this.startRegionRe.test(i))return this.getCommentRegionBlock(e,i,n);var s=i.match(this.foldingStartMarker);if(s){var o=s.index;if(s[1])return this.openingBracketBlock(e,s[1],n,o);var u=e.getCommentFoldRange(n,o+s[0].length,1);return u&&!u.isMultiLine()&&(r?u=this.getSectionRange(e,n):t!="all"&&(u=null)),u}if(t==="markbegin")return;var s=i.match(this.foldingStopMarker);if(s){var o=s.index+s[0].length;return s[1]?this.closingBracketBlock(e,s[1],n,o):e.getCommentFoldRange(n,o,-1)}},this.getSectionRange=function(e,t){var n=e.getLine(t),r=n.search(/\S/),s=t,o=n.length;t+=1;var u=t,a=e.getLength();while(++tf)break;var l=this.getFoldWidgetRange(e,"all",t);if(l){if(l.start.row<=s)break;if(l.isMultiLine())t=l.end.row;else if(r==f)break}u=t}return new i(s,o,u,e.getLine(u).length)},this.getCommentRegionBlock=function(e,t,n){var r=t.search(/\s*$/),s=e.getLength(),o=n,u=/^\s*(?:\/\*|\/\/|--)#?(end)?region\b/,a=1;while(++no)return new i(o,r,l,t.length)}}.call(o.prototype)}),define("ace/mode/folding/csharp",["require","exports","module","ace/lib/oop","ace/range","ace/mode/folding/cstyle"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("../../range").Range,s=e("./cstyle").FoldMode,o=t.FoldMode=function(e){e&&(this.foldingStartMarker=new RegExp(this.foldingStartMarker.source.replace(/\|[^|]*?$/,"|"+e.start)),this.foldingStopMarker=new RegExp(this.foldingStopMarker.source.replace(/\|[^|]*?$/,"|"+e.end)))};r.inherits(o,s),function(){this.usingRe=/^\s*using \S/,this.getFoldWidgetRangeBase=this.getFoldWidgetRange,this.getFoldWidgetBase=this.getFoldWidget,this.getFoldWidget=function(e,t,n){var r=this.getFoldWidgetBase(e,t,n);if(!r){var i=e.getLine(n);if(/^\s*#region\b/.test(i))return"start";var s=this.usingRe;if(s.test(i)){var o=e.getLine(n-1),u=e.getLine(n+1);if(!s.test(o)&&s.test(u))return"start"}}return r},this.getFoldWidgetRange=function(e,t,n){var r=this.getFoldWidgetRangeBase(e,t,n);if(r)return r;var i=e.getLine(n);if(this.usingRe.test(i))return this.getUsingStatementBlock(e,i,n);if(/^\s*#region\b/.test(i))return this.getRegionBlock(e,i,n)},this.getUsingStatementBlock=function(e,t,n){var r=t.match(this.usingRe)[0].length-1,s=e.getLength(),o=n,u=n;while(++no){var a=e.getLine(u).length;return new i(o,r,u,a)}},this.getRegionBlock=function(e,t,n){var r=t.search(/\s*$/),s=e.getLength(),o=n,u=/^\s*#(end)?region\b/,a=1;while(++no)return new i(o,r,l,t.length)}}.call(o.prototype)}),define("ace/mode/csharp",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/csharp_highlight_rules","ace/mode/matching_brace_outdent","ace/mode/behaviour/cstyle","ace/mode/folding/csharp"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./csharp_highlight_rules").CSharpHighlightRules,o=e("./matching_brace_outdent").MatchingBraceOutdent,u=e("./behaviour/cstyle").CstyleBehaviour,a=e("./folding/csharp").FoldMode,f=function(){this.HighlightRules=s,this.$outdent=new o,this.$behaviour=new u,this.foldingRules=new a};r.inherits(f,i),function(){this.lineCommentStart="//",this.blockComment={start:"/*",end:"*/"},this.getNextLineIndent=function(e,t,n){var r=this.$getIndent(t),i=this.getTokenizer().getLineTokens(t,e),s=i.tokens;if(s.length&&s[s.length-1].type=="comment")return r;if(e=="start"){var o=t.match(/^.*[\{\(\[]\s*$/);o&&(r+=n)}return r},this.checkOutdent=function(e,t,n){return this.$outdent.checkOutdent(t,n)},this.autoOutdent=function(e,t,n){this.$outdent.autoOutdent(t,n)},this.createWorker=function(e){return null},this.$id="ace/mode/csharp"}.call(f.prototype),t.Mode=f}); (function() { + window.require(["ace/mode/csharp"], function(m) { + if (typeof module == "object" && typeof exports == "object" && module) { + module.exports = m; + } + }); + })(); + \ No newline at end of file diff --git a/apps/block_scout_web/assets/js/lib/ace/src-min/theme-chrome.js b/apps/block_scout_web/assets/js/lib/ace/src-min/theme-chrome.js new file mode 100644 index 000000000000..c9438609f88f --- /dev/null +++ b/apps/block_scout_web/assets/js/lib/ace/src-min/theme-chrome.js @@ -0,0 +1,8 @@ +/* eslint-disable */define("ace/theme/chrome",["require","exports","module","ace/lib/dom"],function(e,t,n){t.isDark=!1,t.cssClass="ace-chrome",t.cssText='.ace-chrome .ace_gutter {background: #ebebeb;color: #333;overflow : hidden;}.ace-chrome .ace_print-margin {width: 1px;background: #e8e8e8;}.ace-chrome {background-color: #FFFFFF;color: black;}.ace-chrome .ace_cursor {color: black;}.ace-chrome .ace_invisible {color: rgb(191, 191, 191);}.ace-chrome .ace_constant.ace_buildin {color: rgb(88, 72, 246);}.ace-chrome .ace_constant.ace_language {color: rgb(88, 92, 246);}.ace-chrome .ace_constant.ace_library {color: rgb(6, 150, 14);}.ace-chrome .ace_invalid {background-color: rgb(153, 0, 0);color: white;}.ace-chrome .ace_fold {}.ace-chrome .ace_support.ace_function {color: rgb(60, 76, 114);}.ace-chrome .ace_support.ace_constant {color: rgb(6, 150, 14);}.ace-chrome .ace_support.ace_type,.ace-chrome .ace_support.ace_class.ace-chrome .ace_support.ace_other {color: rgb(109, 121, 222);}.ace-chrome .ace_variable.ace_parameter {font-style:italic;color:#FD971F;}.ace-chrome .ace_keyword.ace_operator {color: rgb(104, 118, 135);}.ace-chrome .ace_comment {color: #236e24;}.ace-chrome .ace_comment.ace_doc {color: #236e24;}.ace-chrome .ace_comment.ace_doc.ace_tag {color: #236e24;}.ace-chrome .ace_constant.ace_numeric {color: rgb(0, 0, 205);}.ace-chrome .ace_variable {color: rgb(49, 132, 149);}.ace-chrome .ace_xml-pe {color: rgb(104, 104, 91);}.ace-chrome .ace_entity.ace_name.ace_function {color: #0000A2;}.ace-chrome .ace_heading {color: rgb(12, 7, 255);}.ace-chrome .ace_list {color:rgb(185, 6, 144);}.ace-chrome .ace_marker-layer .ace_selection {background: rgb(181, 213, 255);}.ace-chrome .ace_marker-layer .ace_step {background: rgb(252, 255, 0);}.ace-chrome .ace_marker-layer .ace_stack {background: rgb(164, 229, 101);}.ace-chrome .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid rgb(192, 192, 192);}.ace-chrome .ace_marker-layer .ace_active-line {background: rgba(0, 0, 0, 0.07);}.ace-chrome .ace_gutter-active-line {background-color : #dcdcdc;}.ace-chrome .ace_marker-layer .ace_selected-word {background: rgb(250, 250, 255);border: 1px solid rgb(200, 200, 250);}.ace-chrome .ace_storage,.ace-chrome .ace_keyword,.ace-chrome .ace_meta.ace_tag {color: rgb(147, 15, 128);}.ace-chrome .ace_string.ace_regex {color: rgb(255, 0, 0)}.ace-chrome .ace_string {color: #1A1AA6;}.ace-chrome .ace_entity.ace_other.ace_attribute-name {color: #994409;}.ace-chrome .ace_indent-guide {background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==") right repeat-y;}';var r=e("../lib/dom");r.importCssString(t.cssText,t.cssClass,!1)}); (function() { + window.require(["ace/theme/chrome"], function(m) { + if (typeof module == "object" && typeof exports == "object" && module) { + module.exports = m; + } + }); + })(); + \ No newline at end of file diff --git a/apps/block_scout_web/assets/js/view_specific/address_contract/code_highlighting.js b/apps/block_scout_web/assets/js/view_specific/address_contract/code_highlighting.js index 52569303aabb..ae57b6144b48 100644 --- a/apps/block_scout_web/assets/js/view_specific/address_contract/code_highlighting.js +++ b/apps/block_scout_web/assets/js/view_specific/address_contract/code_highlighting.js @@ -1,6 +1,25 @@ -import hljs from 'highlight.js/lib/core' +import ace from '../../lib/ace/src-min/ace' +import '../../lib/ace/src-min/mode-csharp' +import '../../lib/ace/src-min/theme-chrome' +import $ from 'jquery' -// only activate highlighting on pages with this selector -if (document.querySelectorAll('[data-activate-highlight]').length > 0) { - hljs.highlightAll() +const Mode = ace.require('ace/mode/csharp').Mode + +const codeMain = $('#code_viewer_main') +const code = codeMain.text() +const editor = ace.edit('code_viewer_main') +editor.session.setMode(new Mode()) +editor.setTheme('ace/theme/chrome') +editor.setValue(code, -1) +editor.setOptions({ maxLines: 40, readOnly: true }) + +const len = codeMain.data('additional-sources-length') +for (let i = 0; i < len; i++) { + const tag = 'code_viewer_' + i + const code = $('#' + tag).text() + const editor = ace.edit(tag) + editor.session.setMode(new Mode()) + editor.setTheme('ace/theme/chrome') + editor.setValue(code, -1) + editor.setOptions({ maxLines: 40, readOnly: true }) } diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex index 2a371a92f412..7f2b8dbbe31f 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex @@ -102,12 +102,10 @@ <%= gettext "Copy Source Code" %>
-
-
<%= for {line, number} <- contract_lines_with_index(target_contract.contract_source_code) do %>
<%= line %>
<% end %>
-
+
><%= target_contract.contract_source_code %>
         
 
-        <%= Enum.map(additional_sources, fn additional_source -> %>
+        <%= additional_sources |> Enum.with_index() |> Enum.map(fn {additional_source, index} -> %>
           

<%= additional_source.file_name %>

@@ -115,9 +113,7 @@ <%= gettext "Copy Source Code" %>
-
-
<%= for {line, number} <- contract_lines_with_index(additional_source.contract_source_code) do %>
<%= line %>
<% end %>
-
+
<%= additional_source.contract_source_code %>
           
<% end)%> diff --git a/apps/block_scout_web/priv/gettext/default.pot b/apps/block_scout_web/priv/gettext/default.pot index fe7b187da31f..fe39bcf3bce3 100644 --- a/apps/block_scout_web/priv/gettext/default.pot +++ b/apps/block_scout_web/priv/gettext/default.pot @@ -652,7 +652,7 @@ msgid "Contract" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:126 +#: lib/block_scout_web/templates/address_contract/index.html.eex:122 msgid "Contract ABI" msgstr "" @@ -678,8 +678,8 @@ msgid "Contract Creation" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:142 -#: lib/block_scout_web/templates/address_contract/index.html.eex:157 +#: lib/block_scout_web/templates/address_contract/index.html.eex:138 +#: lib/block_scout_web/templates/address_contract/index.html.eex:153 msgid "Contract Creation Code" msgstr "" @@ -711,7 +711,7 @@ msgid "Contract source code" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:148 +#: lib/block_scout_web/templates/address_contract/index.html.eex:144 msgid "Contracts that self destruct in their constructors have no contract code published and cannot be verified." msgstr "" @@ -721,7 +721,7 @@ msgid "Contribute" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:128 +#: lib/block_scout_web/templates/address_contract/index.html.eex:124 msgid "Copy ABI" msgstr "" @@ -734,8 +734,8 @@ msgid "Copy Address" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:144 -#: lib/block_scout_web/templates/address_contract/index.html.eex:160 +#: lib/block_scout_web/templates/address_contract/index.html.eex:140 +#: lib/block_scout_web/templates/address_contract/index.html.eex:156 msgid "Copy Contract Creation Code" msgstr "" @@ -745,8 +745,8 @@ msgid "Copy Decompiled Contract Code" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:187 -#: lib/block_scout_web/templates/address_contract/index.html.eex:197 +#: lib/block_scout_web/templates/address_contract/index.html.eex:183 +#: lib/block_scout_web/templates/address_contract/index.html.eex:193 msgid "Copy Deployed ByteCode" msgstr "" @@ -781,7 +781,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/address_contract/index.html.eex:102 -#: lib/block_scout_web/templates/address_contract/index.html.eex:115 +#: lib/block_scout_web/templates/address_contract/index.html.eex:113 msgid "Copy Source Code" msgstr "" @@ -951,8 +951,8 @@ msgid "Delegators’ Staked Amount" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:185 -#: lib/block_scout_web/templates/address_contract/index.html.eex:193 +#: lib/block_scout_web/templates/address_contract/index.html.eex:181 +#: lib/block_scout_web/templates/address_contract/index.html.eex:189 msgid "Deployed ByteCode" msgstr "" @@ -975,7 +975,7 @@ msgid "Difficulty" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:149 +#: lib/block_scout_web/templates/address_contract/index.html.eex:145 msgid "Displaying the init data provided of the creating transaction." msgstr "" @@ -1143,7 +1143,7 @@ msgid "Export Data" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:228 +#: lib/block_scout_web/templates/address_contract/index.html.eex:224 msgid "External libraries" msgstr "" @@ -2981,9 +2981,9 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/address_contract/index.html.eex:27 -#: lib/block_scout_web/templates/address_contract/index.html.eex:29 lib/block_scout_web/templates/address_contract/index.html.eex:164 -#: lib/block_scout_web/templates/address_contract/index.html.eex:170 lib/block_scout_web/templates/address_contract/index.html.eex:201 -#: lib/block_scout_web/templates/address_contract/index.html.eex:207 lib/block_scout_web/templates/smart_contract/_functions.html.eex:14 +#: lib/block_scout_web/templates/address_contract/index.html.eex:29 lib/block_scout_web/templates/address_contract/index.html.eex:160 +#: lib/block_scout_web/templates/address_contract/index.html.eex:166 lib/block_scout_web/templates/address_contract/index.html.eex:197 +#: lib/block_scout_web/templates/address_contract/index.html.eex:203 lib/block_scout_web/templates/smart_contract/_functions.html.eex:14 msgid "Verify & Publish" msgstr "" diff --git a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po index fe7b187da31f..fe39bcf3bce3 100644 --- a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po +++ b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po @@ -652,7 +652,7 @@ msgid "Contract" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:126 +#: lib/block_scout_web/templates/address_contract/index.html.eex:122 msgid "Contract ABI" msgstr "" @@ -678,8 +678,8 @@ msgid "Contract Creation" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:142 -#: lib/block_scout_web/templates/address_contract/index.html.eex:157 +#: lib/block_scout_web/templates/address_contract/index.html.eex:138 +#: lib/block_scout_web/templates/address_contract/index.html.eex:153 msgid "Contract Creation Code" msgstr "" @@ -711,7 +711,7 @@ msgid "Contract source code" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:148 +#: lib/block_scout_web/templates/address_contract/index.html.eex:144 msgid "Contracts that self destruct in their constructors have no contract code published and cannot be verified." msgstr "" @@ -721,7 +721,7 @@ msgid "Contribute" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:128 +#: lib/block_scout_web/templates/address_contract/index.html.eex:124 msgid "Copy ABI" msgstr "" @@ -734,8 +734,8 @@ msgid "Copy Address" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:144 -#: lib/block_scout_web/templates/address_contract/index.html.eex:160 +#: lib/block_scout_web/templates/address_contract/index.html.eex:140 +#: lib/block_scout_web/templates/address_contract/index.html.eex:156 msgid "Copy Contract Creation Code" msgstr "" @@ -745,8 +745,8 @@ msgid "Copy Decompiled Contract Code" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:187 -#: lib/block_scout_web/templates/address_contract/index.html.eex:197 +#: lib/block_scout_web/templates/address_contract/index.html.eex:183 +#: lib/block_scout_web/templates/address_contract/index.html.eex:193 msgid "Copy Deployed ByteCode" msgstr "" @@ -781,7 +781,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/address_contract/index.html.eex:102 -#: lib/block_scout_web/templates/address_contract/index.html.eex:115 +#: lib/block_scout_web/templates/address_contract/index.html.eex:113 msgid "Copy Source Code" msgstr "" @@ -951,8 +951,8 @@ msgid "Delegators’ Staked Amount" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:185 -#: lib/block_scout_web/templates/address_contract/index.html.eex:193 +#: lib/block_scout_web/templates/address_contract/index.html.eex:181 +#: lib/block_scout_web/templates/address_contract/index.html.eex:189 msgid "Deployed ByteCode" msgstr "" @@ -975,7 +975,7 @@ msgid "Difficulty" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:149 +#: lib/block_scout_web/templates/address_contract/index.html.eex:145 msgid "Displaying the init data provided of the creating transaction." msgstr "" @@ -1143,7 +1143,7 @@ msgid "Export Data" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:228 +#: lib/block_scout_web/templates/address_contract/index.html.eex:224 msgid "External libraries" msgstr "" @@ -2981,9 +2981,9 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/address_contract/index.html.eex:27 -#: lib/block_scout_web/templates/address_contract/index.html.eex:29 lib/block_scout_web/templates/address_contract/index.html.eex:164 -#: lib/block_scout_web/templates/address_contract/index.html.eex:170 lib/block_scout_web/templates/address_contract/index.html.eex:201 -#: lib/block_scout_web/templates/address_contract/index.html.eex:207 lib/block_scout_web/templates/smart_contract/_functions.html.eex:14 +#: lib/block_scout_web/templates/address_contract/index.html.eex:29 lib/block_scout_web/templates/address_contract/index.html.eex:160 +#: lib/block_scout_web/templates/address_contract/index.html.eex:166 lib/block_scout_web/templates/address_contract/index.html.eex:197 +#: lib/block_scout_web/templates/address_contract/index.html.eex:203 lib/block_scout_web/templates/smart_contract/_functions.html.eex:14 msgid "Verify & Publish" msgstr "" From dd4146ef761bc864d77f24f2b13343f3a9e55c13 Mon Sep 17 00:00:00 2001 From: nikitosing Date: Tue, 3 May 2022 13:48:04 +0300 Subject: [PATCH 075/128] Fix js import --- .../js/view_specific/address_contract/code_highlighting.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/block_scout_web/assets/js/view_specific/address_contract/code_highlighting.js b/apps/block_scout_web/assets/js/view_specific/address_contract/code_highlighting.js index ae57b6144b48..ae030c071915 100644 --- a/apps/block_scout_web/assets/js/view_specific/address_contract/code_highlighting.js +++ b/apps/block_scout_web/assets/js/view_specific/address_contract/code_highlighting.js @@ -1,12 +1,14 @@ -import ace from '../../lib/ace/src-min/ace' +import '../../lib/ace/src-min/ace' import '../../lib/ace/src-min/mode-csharp' import '../../lib/ace/src-min/theme-chrome' import $ from 'jquery' +/* eslint-disable-next-line */ const Mode = ace.require('ace/mode/csharp').Mode const codeMain = $('#code_viewer_main') const code = codeMain.text() +/* eslint-disable-next-line */ const editor = ace.edit('code_viewer_main') editor.session.setMode(new Mode()) editor.setTheme('ace/theme/chrome') @@ -17,6 +19,7 @@ const len = codeMain.data('additional-sources-length') for (let i = 0; i < len; i++) { const tag = 'code_viewer_' + i const code = $('#' + tag).text() + /* eslint-disable-next-line */ const editor = ace.edit(tag) editor.session.setMode(new Mode()) editor.setTheme('ace/theme/chrome') From b36b493920b17377cbe917d9b73a859cc5efc454 Mon Sep 17 00:00:00 2001 From: nikitosing Date: Tue, 3 May 2022 14:28:09 +0300 Subject: [PATCH 076/128] Remove vertical line --- .../js/view_specific/address_contract/code_highlighting.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/block_scout_web/assets/js/view_specific/address_contract/code_highlighting.js b/apps/block_scout_web/assets/js/view_specific/address_contract/code_highlighting.js index ae030c071915..fde8bc2b135a 100644 --- a/apps/block_scout_web/assets/js/view_specific/address_contract/code_highlighting.js +++ b/apps/block_scout_web/assets/js/view_specific/address_contract/code_highlighting.js @@ -13,7 +13,7 @@ const editor = ace.edit('code_viewer_main') editor.session.setMode(new Mode()) editor.setTheme('ace/theme/chrome') editor.setValue(code, -1) -editor.setOptions({ maxLines: 40, readOnly: true }) +editor.setOptions({ maxLines: 40, readOnly: true, printMargin: false }) const len = codeMain.data('additional-sources-length') for (let i = 0; i < len; i++) { From 8df21b369ac3cef5ae757b5f744f80716223c770 Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Wed, 4 May 2022 15:08:21 +0300 Subject: [PATCH 077/128] Token balances fetcher retry --- CHANGELOG.md | 1 + .../lib/indexer/fetcher/token_balance.ex | 29 +++- apps/indexer/lib/indexer/token_balances.ex | 8 +- .../indexer/fetcher/token_balance_test.exs | 48 ++++++ .../test/indexer/token_balances_test.exs | 149 ++++++++++-------- 5 files changed, 168 insertions(+), 67 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d46f034619a3..e772b2815047 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - [#5268](https://github.com/blockscout/blockscout/pull/5268), [#5313](https://github.com/blockscout/blockscout/pull/5313) - Contract names display improvement ### Fixes +- [#5528](https://github.com/blockscout/blockscout/pull/5528) - Token balances fetcher retry - [#5524](https://github.com/blockscout/blockscout/pull/5524) - ContractState module resistance to unresponsive archive node - [#5513](https://github.com/blockscout/blockscout/pull/5513) - Do not fill pending blocks ops with block numbers below TRACE_FIRST_BLOCK - [#5508](https://github.com/blockscout/blockscout/pull/5508) - Hide indexing banner if we fetched internal transactions from TRACE_FIRST_BLOCK diff --git a/apps/indexer/lib/indexer/fetcher/token_balance.ex b/apps/indexer/lib/indexer/fetcher/token_balance.ex index 9af2d7b34476..b23978facd60 100644 --- a/apps/indexer/lib/indexer/fetcher/token_balance.ex +++ b/apps/indexer/lib/indexer/fetcher/token_balance.ex @@ -81,7 +81,7 @@ defmodule Indexer.Fetcher.TokenBalance do result = entries |> Enum.map(&format_params/1) - |> Enum.map(&Map.put(&1, :retries_count, &1.retries_count + 1)) + |> increase_retries_count() |> fetch_from_blockchain() |> import_token_balances() @@ -100,9 +100,32 @@ defmodule Indexer.Fetcher.TokenBalance do Logger.metadata(count: Enum.count(retryable_params_list)) - {:ok, token_balances} = TokenBalances.fetch_token_balances_from_blockchain(retryable_params_list) + %{fetched_token_balances: fetched_token_balances, failed_token_balances: _failed_token_balances} = + 1..@max_retries + |> Enum.reduce_while(%{fetched_token_balances: [], failed_token_balances: retryable_params_list}, fn _x, acc -> + {:ok, + %{fetched_token_balances: _fetched_token_balances, failed_token_balances: failed_token_balances} = + token_balances} = TokenBalances.fetch_token_balances_from_blockchain(acc.failed_token_balances) - token_balances + if Enum.empty?(failed_token_balances) do + {:halt, token_balances} + else + failed_token_balances = increase_retries_count(failed_token_balances) + + token_balances_updated_retries_count = + token_balances + |> Map.put(:failed_token_balances, failed_token_balances) + + {:cont, token_balances_updated_retries_count} + end + end) + + fetched_token_balances + end + + defp increase_retries_count(params_list) do + params_list + |> Enum.map(&Map.put(&1, :retries_count, &1.retries_count + 1)) end def import_token_balances(token_balances_params) do diff --git a/apps/indexer/lib/indexer/token_balances.ex b/apps/indexer/lib/indexer/token_balances.ex index 3e60f2326080..e53347f90ba9 100644 --- a/apps/indexer/lib/indexer/token_balances.ex +++ b/apps/indexer/lib/indexer/token_balances.ex @@ -87,7 +87,13 @@ defmodule Indexer.TokenBalances do |> unfetched_token_balances(fetched_token_balances) |> schedule_token_balances - {:ok, fetched_token_balances} + failed_token_balances = + requested_token_balances + |> MapSet.new() + |> MapSet.difference(MapSet.new(fetched_token_balances)) + |> MapSet.to_list() + + {:ok, %{fetched_token_balances: fetched_token_balances, failed_token_balances: failed_token_balances}} end def to_address_current_token_balances(address_token_balances) when is_list(address_token_balances) do diff --git a/apps/indexer/test/indexer/fetcher/token_balance_test.exs b/apps/indexer/test/indexer/fetcher/token_balance_test.exs index 739182174f9e..6c090973fd1c 100644 --- a/apps/indexer/test/indexer/fetcher/token_balance_test.exs +++ b/apps/indexer/test/indexer/fetcher/token_balance_test.exs @@ -68,6 +68,54 @@ defmodule Indexer.Fetcher.TokenBalanceTest do assert token_balance_updated.value_fetched_at != nil end + test "imports the given token balances from 2nd retry" do + %Address.TokenBalance{ + address_hash: %Hash{bytes: address_hash_bytes} = address_hash, + token_contract_address_hash: %Hash{bytes: token_contract_address_hash_bytes}, + block_number: block_number + } = insert(:token_balance, value_fetched_at: nil, value: nil) + + expect( + EthereumJSONRPC.Mox, + :json_rpc, + fn [%{id: id, method: "eth_call", params: [%{data: _, to: _}, _]}], _options -> + {:ok, + [ + %{ + id: id, + jsonrpc: "2.0", + error: %{code: -32015, message: "VM execution error.", data: ""} + } + ]} + end + ) + + expect( + EthereumJSONRPC.Mox, + :json_rpc, + fn [%{id: id, method: "eth_call", params: [%{data: _, to: _}, _]}], _options -> + {:ok, + [ + %{ + id: id, + jsonrpc: "2.0", + result: "0x00000000000000000000000000000000000000000000d3c21bcecceda1000000" + } + ]} + end + ) + + assert TokenBalance.run( + [{address_hash_bytes, token_contract_address_hash_bytes, block_number, "ERC-20", nil, 0}], + nil + ) == :ok + + token_balance_updated = Explorer.Repo.get_by(Address.TokenBalance, address_hash: address_hash) + + assert token_balance_updated.value == Decimal.new(1_000_000_000_000_000_000_000_000) + assert token_balance_updated.value_fetched_at != nil + end + test "does not try to fetch the token balance again if the retry is over" do max_retries = 3 diff --git a/apps/indexer/test/indexer/token_balances_test.exs b/apps/indexer/test/indexer/token_balances_test.exs index 12cddcaa136b..2f5c89c1a6dc 100644 --- a/apps/indexer/test/indexer/token_balances_test.exs +++ b/apps/indexer/test/indexer/token_balances_test.exs @@ -46,7 +46,7 @@ defmodule Indexer.TokenBalancesTest do address_hash: ^address_hash_string, block_number: 1_000, value_fetched_at: _ - } = List.first(result) + } = List.first(result.fetched_token_balances) end test "fetches balances of ERC-1155 tokens" do @@ -74,15 +74,18 @@ defmodule Indexer.TokenBalancesTest do {:ok, result} = TokenBalances.fetch_token_balances_from_blockchain(data) - assert [ - %{ - value: 2, - token_contract_address_hash: ^token_contract_address_hash, - address_hash: ^address_hash_string, - block_number: 1_000, - value_fetched_at: _ - } - ] = result + assert %{ + failed_token_balances: [], + fetched_token_balances: [ + %{ + value: 2, + token_contract_address_hash: ^token_contract_address_hash, + address_hash: ^address_hash_string, + block_number: 1_000, + value_fetched_at: _ + } + ] + } = result end test "fetches multiple balances of tokens" do @@ -166,60 +169,63 @@ defmodule Indexer.TokenBalancesTest do {:ok, result} = TokenBalances.fetch_token_balances_from_blockchain(data) - assert [ - %{ - value: 1_000_000_000_000_000_000_000_000, - token_contract_address_hash: ^token_1_contract_address_hash, - address_hash: ^address_1_hash_string, - block_number: 1_000, - value_fetched_at: _ - }, - %{ - value: 3_000_000_000_000_000_000_000_000_000, - token_contract_address_hash: ^token_2_contract_address_hash, - address_hash: ^address_2_hash_string, - block_number: 1_000, - value_fetched_at: _ - }, - %{ - value: 1, - token_contract_address_hash: ^token_3_contract_address_hash, - address_hash: ^address_2_hash_string, - block_number: 1_000, - value_fetched_at: _ - }, - %{ - value: 6_000_000_000_000_000_000_000_000_000, - token_contract_address_hash: ^token_2_contract_address_hash, - address_hash: ^token_2_contract_address_hash, - block_number: 1_000, - value_fetched_at: _ - }, - %{ - value: 5_000_000_000_000_000_000_000_000_000, - token_contract_address_hash: ^token_2_contract_address_hash, - address_hash: ^address_3_hash_string, - block_number: 1_000, - value_fetched_at: _ - }, - %{ - value: 6_000_000_000_000_000_000_000_000_000, - token_contract_address_hash: ^token_2_contract_address_hash, - address_hash: ^token_2_contract_address_hash, - block_number: 1_000, - value_fetched_at: _ - }, - %{ - value: 2, - token_contract_address_hash: ^token_4_contract_address_hash, - address_hash: ^address_2_hash_string, - block_number: 1_000, - value_fetched_at: _ - } - ] = result + assert %{ + failed_token_balances: [], + fetched_token_balances: [ + %{ + value: 1_000_000_000_000_000_000_000_000, + token_contract_address_hash: ^token_1_contract_address_hash, + address_hash: ^address_1_hash_string, + block_number: 1_000, + value_fetched_at: _ + }, + %{ + value: 3_000_000_000_000_000_000_000_000_000, + token_contract_address_hash: ^token_2_contract_address_hash, + address_hash: ^address_2_hash_string, + block_number: 1_000, + value_fetched_at: _ + }, + %{ + value: 1, + token_contract_address_hash: ^token_3_contract_address_hash, + address_hash: ^address_2_hash_string, + block_number: 1_000, + value_fetched_at: _ + }, + %{ + value: 6_000_000_000_000_000_000_000_000_000, + token_contract_address_hash: ^token_2_contract_address_hash, + address_hash: ^token_2_contract_address_hash, + block_number: 1_000, + value_fetched_at: _ + }, + %{ + value: 5_000_000_000_000_000_000_000_000_000, + token_contract_address_hash: ^token_2_contract_address_hash, + address_hash: ^address_3_hash_string, + block_number: 1_000, + value_fetched_at: _ + }, + %{ + value: 6_000_000_000_000_000_000_000_000_000, + token_contract_address_hash: ^token_2_contract_address_hash, + address_hash: ^token_2_contract_address_hash, + block_number: 1_000, + value_fetched_at: _ + }, + %{ + value: 2, + token_contract_address_hash: ^token_4_contract_address_hash, + address_hash: ^address_2_hash_string, + block_number: 1_000, + value_fetched_at: _ + } + ] + } = result end - test "ignores calls that gave errors to try fetch they again later" do + test "returns calls that gave errors to try fetch they again later" do address = insert(:address, hash: "0x7113ffcb9c18a97da1b9cfc43e6cb44ed9165509") token = insert(:token, contract_address: build(:contract_address)) @@ -236,7 +242,24 @@ defmodule Indexer.TokenBalancesTest do get_balance_from_blockchain_with_error() - assert TokenBalances.fetch_token_balances_from_blockchain(token_balances) == {:ok, []} + assert TokenBalances.fetch_token_balances_from_blockchain(token_balances) == + {:ok, + %{ + failed_token_balances: [ + %{ + address_hash: "0x7113ffcb9c18a97da1b9cfc43e6cb44ed9165509", + block_number: 1000, + error: "(-32015) VM execution error. (Reverted 0x)", + retries_count: 1, + token_contract_address_hash: to_string(token.contract_address_hash), + token_id: 11, + token_type: "ERC-20", + value: nil, + value_fetched_at: nil + } + ], + fetched_token_balances: [] + }} end end From fc46b86b57ff609df5069b58618558f817876847 Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Wed, 4 May 2022 20:46:07 +0300 Subject: [PATCH 078/128] Remove unused bridged_tokens_eth_enabled? bridged_tokens_bsc_enabled? functions --- apps/explorer/lib/explorer/chain.ex | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index ad1f79af3e43..44dc20968d74 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -7068,18 +7068,6 @@ defmodule Explorer.Chain do (bsc_omni_bridge_mediator && bsc_omni_bridge_mediator !== "") end - def bridged_tokens_eth_enabled? do - eth_omni_bridge_mediator = Application.get_env(:block_scout_web, :eth_omni_bridge_mediator) - - eth_omni_bridge_mediator && eth_omni_bridge_mediator !== "" - end - - def bridged_tokens_bsc_enabled? do - bsc_omni_bridge_mediator = Application.get_env(:block_scout_web, :bsc_omni_bridge_mediator) - - bsc_omni_bridge_mediator && bsc_omni_bridge_mediator !== "" - end - def chain_id_display_name(nil), do: "" def chain_id_display_name(chain_id) do From 347cfe62c4d63ab07f5e61d9a55ca6fb36c57a8a Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Thu, 5 May 2022 14:52:37 +0300 Subject: [PATCH 079/128] Blockscout v4.1.3 --- CHANGELOG.md | 9 +++++++++ mix.exs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index decf0a003139..20030c308954 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ ## Current +### Features + +### Fixes + +### Chore + + +## 4.1.3-beta + ### Features - [#5515](https://github.com/blockscout/blockscout/pull/5515) - Integrate ace editor to display contract sources - [#5505](https://github.com/blockscout/blockscout/pull/5505) - Manage debug_traceTransaction JSON RPC method timeout diff --git a/mix.exs b/mix.exs index bbf55f4c9951..7cacca369098 100644 --- a/mix.exs +++ b/mix.exs @@ -7,7 +7,7 @@ defmodule BlockScout.Mixfile do [ app: :block_scout, # aliases: aliases(config_env()), - version: "4.1.2", + version: "4.1.3", apps_path: "apps", deps: deps(), dialyzer: dialyzer(), From b003e397ecadfd80ffafd56d1cc48df8844a0558 Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Thu, 5 May 2022 18:44:26 +0300 Subject: [PATCH 080/128] NPM audit fix --- .github/workflows/publish-docker-image.yml | 2 +- CHANGELOG.md | 1 + apps/block_scout_web/assets/package-lock.json | 318 ++++++++++-------- 3 files changed, 186 insertions(+), 135 deletions(-) diff --git a/.github/workflows/publish-docker-image.yml b/.github/workflows/publish-docker-image.yml index f0effec8398e..e6e1e5d0e7bd 100644 --- a/.github/workflows/publish-docker-image.yml +++ b/.github/workflows/publish-docker-image.yml @@ -14,7 +14,7 @@ jobs: name: Push Docker image to Docker Hub runs-on: ubuntu-latest env: - RELEASE_VERSION: 4.1.3 + RELEASE_VERSION: 4.1.4 steps: - name: Check out the repo uses: actions/checkout@v2 diff --git a/CHANGELOG.md b/CHANGELOG.md index 20030c308954..af96b8418f7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Fixes ### Chore +- [#5536](https://github.com/blockscout/blockscout/pull/5536) - NPM audit fix ## 4.1.3-beta diff --git a/apps/block_scout_web/assets/package-lock.json b/apps/block_scout_web/assets/package-lock.json index 13898d4dd733..84641be966e4 100644 --- a/apps/block_scout_web/assets/package-lock.json +++ b/apps/block_scout_web/assets/package-lock.json @@ -3303,12 +3303,12 @@ "dev": true }, "node_modules/@walletconnect/browser-utils": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@walletconnect/browser-utils/-/browser-utils-1.7.5.tgz", - "integrity": "sha512-gm9ufi0n5cGBXoGWDtMVSqIJ0eXYW+ZFuTNVN0fm4oal26J7cPrOdFjzhv5zvx5fKztWQ21DNFZ+PRXBjXg04Q==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@walletconnect/browser-utils/-/browser-utils-1.7.8.tgz", + "integrity": "sha512-iCL0XCWOZaABIc0lqA79Vyaybr3z26nt8mxiwvfrG8oaKUf5Y21Of4dj+wIXQ4Hhblre6SgDlU0Ffb39+1THOw==", "dependencies": { "@walletconnect/safe-json": "1.0.0", - "@walletconnect/types": "^1.7.5", + "@walletconnect/types": "^1.7.8", "@walletconnect/window-getters": "1.0.0", "@walletconnect/window-metadata": "1.0.0", "detect-browser": "5.2.0" @@ -3320,24 +3320,24 @@ "integrity": "sha512-tr7XntDAu50BVENgQfajMLzacmSe34D+qZc4zjnniz0ZVuw/TZcLcyxHQjYpJTM36sGEkZZlYLnIM1hH7alTMA==" }, "node_modules/@walletconnect/client": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@walletconnect/client/-/client-1.7.5.tgz", - "integrity": "sha512-Vh3h1kfhmJ4Jx//H0lmmfDc5Q2s+R73Nh5cetVN41QPRrAcqHE4lR2ZS8XxRCNBl4/gcHZJIZS9J2Ui4tTXBLA==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@walletconnect/client/-/client-1.7.8.tgz", + "integrity": "sha512-pBroM6jZAaUM0SoXJZg5U7aPTiU3ljQAw3Xh/i2pxFDeN/oPKao7husZ5rdxS5xuGSV6YpqqRb0RxW1IeoR2Pg==", "dependencies": { - "@walletconnect/core": "^1.7.5", - "@walletconnect/iso-crypto": "^1.7.5", - "@walletconnect/types": "^1.7.5", - "@walletconnect/utils": "^1.7.5" + "@walletconnect/core": "^1.7.8", + "@walletconnect/iso-crypto": "^1.7.8", + "@walletconnect/types": "^1.7.8", + "@walletconnect/utils": "^1.7.8" } }, "node_modules/@walletconnect/core": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-1.7.5.tgz", - "integrity": "sha512-c4B8s9fZ/Ah2p460Hxo4e9pwLQVYT2+dVYAfqaxVzfYjhAokDEtO55Bdm1hujtRjQVqwTvCljKxBB+LgMp3k8w==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-1.7.8.tgz", + "integrity": "sha512-9xcQ0YNf9JUFb0YOX1Mpy4Yojt+6w2yQz/0aIEyj2X/s9D71NW0fTYsMcdhkLOI7mn2cqVbx2t1lRvdgqsbrSQ==", "dependencies": { - "@walletconnect/socket-transport": "^1.7.5", - "@walletconnect/types": "^1.7.5", - "@walletconnect/utils": "^1.7.5" + "@walletconnect/socket-transport": "^1.7.8", + "@walletconnect/types": "^1.7.8", + "@walletconnect/utils": "^1.7.8" } }, "node_modules/@walletconnect/crypto": { @@ -3367,12 +3367,12 @@ "integrity": "sha512-4BwqyWy6KpSvkocSaV7WR3BlZfrxLbJSLkg+j7Gl6pTDE+U55lLhJvQaMuDVazXYxcjBsG09k7UlH7cGiUI5vQ==" }, "node_modules/@walletconnect/http-connection": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@walletconnect/http-connection/-/http-connection-1.7.5.tgz", - "integrity": "sha512-WDy2Y/07c1F107362jel0voeV6QMJuWbwAKNLtxlX8Y9KNzqZAGlHhIZykSWrMjNGwxBaXoqLPmu60uVvodc6A==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@walletconnect/http-connection/-/http-connection-1.7.8.tgz", + "integrity": "sha512-31gjBw46MRU9hFMTNXAqh+f8qpDNzVeV9BJehzVWKiNC3ciL1JCZkbvsY0djwajduE6TB2ujaML0XDXS9HgBRA==", "dependencies": { - "@walletconnect/types": "^1.7.5", - "@walletconnect/utils": "^1.7.5", + "@walletconnect/types": "^1.7.8", + "@walletconnect/utils": "^1.7.8", "eventemitter3": "4.0.7", "xhr2-cookies": "1.1.0" } @@ -3383,13 +3383,13 @@ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" }, "node_modules/@walletconnect/iso-crypto": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@walletconnect/iso-crypto/-/iso-crypto-1.7.5.tgz", - "integrity": "sha512-mJdRs2SqAPOLBBqLhU+ZnAh2c8TL2uDuL/ojV4aBzZ0ZHNT7X2zSOjAiixCb3vvH8GAt30OKmiRo3+ChI/9zvA==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@walletconnect/iso-crypto/-/iso-crypto-1.7.8.tgz", + "integrity": "sha512-Qo6qDcMG0Ac+9fpWE0h/oE55NHLk6eM2vlXpWlQDN/me7RZGrkvk+LXsAkQ3UiYPEiPfq4eswcyRWC9AcrAscg==", "dependencies": { "@walletconnect/crypto": "^1.0.2", - "@walletconnect/types": "^1.7.5", - "@walletconnect/utils": "^1.7.5" + "@walletconnect/types": "^1.7.8", + "@walletconnect/utils": "^1.7.8" } }, "node_modules/@walletconnect/jsonrpc-types": { @@ -3416,13 +3416,13 @@ "deprecated": "Deprecated in favor of dynamic registry available from: https://github.com/walletconnect/walletconnect-registry" }, "node_modules/@walletconnect/qrcode-modal": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@walletconnect/qrcode-modal/-/qrcode-modal-1.7.5.tgz", - "integrity": "sha512-LVq35jc3VMGq1EMcGCObQtEiercMDmUHDnc7A3AmUo0LoAbaPo6c8Hq0zqy2+JhtLmxUhU3ktf+szmCoiUDTUQ==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@walletconnect/qrcode-modal/-/qrcode-modal-1.7.8.tgz", + "integrity": "sha512-LqNJMLWO+ljvoRSdq8tcEslW0imKrrb+ugs3bw4w/jEI1FSJzVeinEsgVpyaMv8wsUcyTcSCXSkXpT1SXHtcpw==", "dependencies": { - "@walletconnect/browser-utils": "^1.7.5", + "@walletconnect/browser-utils": "^1.7.8", "@walletconnect/mobile-registry": "^1.4.0", - "@walletconnect/types": "^1.7.5", + "@walletconnect/types": "^1.7.8", "copy-to-clipboard": "^3.3.1", "preact": "10.4.1", "qrcode": "1.4.4" @@ -3444,12 +3444,12 @@ "integrity": "sha512-QJzp/S/86sUAgWY6eh5MKYmSfZaRpIlmCJdi5uG4DJlKkZrHEF7ye7gA+VtbVzvTtpM/gRwO2plQuiooIeXjfg==" }, "node_modules/@walletconnect/socket-transport": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@walletconnect/socket-transport/-/socket-transport-1.7.5.tgz", - "integrity": "sha512-4TYCxrNWb4f5a1NGsALXidr+/6dOiqgVfUQJ4fdP6R7ijL+7jtdiktguU9FIDq5wFXRE+ZdpCpwSAfOt60q/mQ==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@walletconnect/socket-transport/-/socket-transport-1.7.8.tgz", + "integrity": "sha512-bqEjLxfSzG79v2OT7XVOZoyUkg6g3yng0fURrdLusWs42fYHWnrSrIZDejFn8N5PiZk5R2edrggkQ7w0VUUAfw==", "dependencies": { - "@walletconnect/types": "^1.7.5", - "@walletconnect/utils": "^1.7.5", + "@walletconnect/types": "^1.7.8", + "@walletconnect/utils": "^1.7.8", "ws": "7.5.3" } }, @@ -3474,19 +3474,19 @@ } }, "node_modules/@walletconnect/types": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-1.7.5.tgz", - "integrity": "sha512-0HvZzxD93et4DdrYgAvclI1BqclkZS7iPWRtbGg3r+PQhRPbOkNypzBy6XH6wflbmr+WBGdmyJvynHsdhcCqUA==" + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-1.7.8.tgz", + "integrity": "sha512-0oSZhKIrtXRJVP1jQ0EDTRtotQY6kggGjDcmm/LLQBKnOZXdPeo0sPkV/7DjT5plT3O7Cjc6JvuXt9WOY0hlCA==" }, "node_modules/@walletconnect/utils": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-1.7.5.tgz", - "integrity": "sha512-U954rIIA/g/Cmdqy+n3hMY1DDMmXxGs8w/QmrK9b/H5nkQ3e4QicOyynq5g/JTTesN5HZdDTFiyX9r0GSKa+iA==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-1.7.8.tgz", + "integrity": "sha512-DSpfH6Do0TQmdrgzu+SyjVhupVjN0WEMvNWGK9K4VlSmLFpCWfme7qxzrvuxBZ47gDqs1kGWvjyJmviWqvOnAg==", "dependencies": { - "@walletconnect/browser-utils": "^1.7.5", + "@walletconnect/browser-utils": "^1.7.8", "@walletconnect/encoding": "^1.0.1", "@walletconnect/jsonrpc-utils": "^1.0.0", - "@walletconnect/types": "^1.7.5", + "@walletconnect/types": "^1.7.8", "bn.js": "4.11.8", "js-sha3": "0.8.0", "query-string": "6.13.5" @@ -3522,15 +3522,15 @@ } }, "node_modules/@walletconnect/web3-provider": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@walletconnect/web3-provider/-/web3-provider-1.7.5.tgz", - "integrity": "sha512-x+UWOTu7jd9qog9NWhaspOmVRDJPnQrgZBscnaSC+x/aAsi52VUrd1GZ9c5UNZFgss41fdx3Z2KhkPeVrlrbuQ==", - "dependencies": { - "@walletconnect/client": "^1.7.5", - "@walletconnect/http-connection": "^1.7.5", - "@walletconnect/qrcode-modal": "^1.7.5", - "@walletconnect/types": "^1.7.5", - "@walletconnect/utils": "^1.7.5", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@walletconnect/web3-provider/-/web3-provider-1.7.8.tgz", + "integrity": "sha512-2VxGo7KPfQTWRJ+rygt3ok/u04InkVE+H9LBIF/RMUwcwyGf2nsP3CcYZVcg3yYpacgN7bAZCersCEYwU8AeeA==", + "dependencies": { + "@walletconnect/client": "^1.7.8", + "@walletconnect/http-connection": "^1.7.8", + "@walletconnect/qrcode-modal": "^1.7.8", + "@walletconnect/types": "^1.7.8", + "@walletconnect/utils": "^1.7.8", "web3-provider-engine": "16.0.1" } }, @@ -4128,9 +4128,9 @@ } }, "node_modules/async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", "dependencies": { "lodash": "^4.17.14" } @@ -5652,12 +5652,12 @@ } }, "node_modules/cross-fetch": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-2.2.5.tgz", - "integrity": "sha512-xqYAhQb4NhCJSRym03dwxpP1bYXpK3y7UN83Bo2WFi3x1Zmzn0SL/6xGoPr+gpt4WmNrgCCX3HPysvOwFOW36w==", + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-2.2.6.tgz", + "integrity": "sha512-9JZz+vXCmfKUZ68zAptS7k4Nu8e2qcibe7WVZYps7sAgk5R8GYTc+T1WR0v1rlP9HxgARmOX1UTIJZFytajpNA==", "dependencies": { - "node-fetch": "2.6.1", - "whatwg-fetch": "2.0.4" + "node-fetch": "^2.6.7", + "whatwg-fetch": "^2.0.4" } }, "node_modules/cross-spawn": { @@ -6535,7 +6535,6 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "dev": true, "optional": true, "peer": true, "dependencies": { @@ -6546,7 +6545,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, "optional": true, "peer": true, "dependencies": { @@ -12973,11 +12971,41 @@ "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==" }, "node_modules/node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, "engines": { "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" } }, "node_modules/node-gyp": { @@ -20534,12 +20562,12 @@ "dev": true }, "@walletconnect/browser-utils": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@walletconnect/browser-utils/-/browser-utils-1.7.5.tgz", - "integrity": "sha512-gm9ufi0n5cGBXoGWDtMVSqIJ0eXYW+ZFuTNVN0fm4oal26J7cPrOdFjzhv5zvx5fKztWQ21DNFZ+PRXBjXg04Q==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@walletconnect/browser-utils/-/browser-utils-1.7.8.tgz", + "integrity": "sha512-iCL0XCWOZaABIc0lqA79Vyaybr3z26nt8mxiwvfrG8oaKUf5Y21Of4dj+wIXQ4Hhblre6SgDlU0Ffb39+1THOw==", "requires": { "@walletconnect/safe-json": "1.0.0", - "@walletconnect/types": "^1.7.5", + "@walletconnect/types": "^1.7.8", "@walletconnect/window-getters": "1.0.0", "@walletconnect/window-metadata": "1.0.0", "detect-browser": "5.2.0" @@ -20553,24 +20581,24 @@ } }, "@walletconnect/client": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@walletconnect/client/-/client-1.7.5.tgz", - "integrity": "sha512-Vh3h1kfhmJ4Jx//H0lmmfDc5Q2s+R73Nh5cetVN41QPRrAcqHE4lR2ZS8XxRCNBl4/gcHZJIZS9J2Ui4tTXBLA==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@walletconnect/client/-/client-1.7.8.tgz", + "integrity": "sha512-pBroM6jZAaUM0SoXJZg5U7aPTiU3ljQAw3Xh/i2pxFDeN/oPKao7husZ5rdxS5xuGSV6YpqqRb0RxW1IeoR2Pg==", "requires": { - "@walletconnect/core": "^1.7.5", - "@walletconnect/iso-crypto": "^1.7.5", - "@walletconnect/types": "^1.7.5", - "@walletconnect/utils": "^1.7.5" + "@walletconnect/core": "^1.7.8", + "@walletconnect/iso-crypto": "^1.7.8", + "@walletconnect/types": "^1.7.8", + "@walletconnect/utils": "^1.7.8" } }, "@walletconnect/core": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-1.7.5.tgz", - "integrity": "sha512-c4B8s9fZ/Ah2p460Hxo4e9pwLQVYT2+dVYAfqaxVzfYjhAokDEtO55Bdm1hujtRjQVqwTvCljKxBB+LgMp3k8w==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-1.7.8.tgz", + "integrity": "sha512-9xcQ0YNf9JUFb0YOX1Mpy4Yojt+6w2yQz/0aIEyj2X/s9D71NW0fTYsMcdhkLOI7mn2cqVbx2t1lRvdgqsbrSQ==", "requires": { - "@walletconnect/socket-transport": "^1.7.5", - "@walletconnect/types": "^1.7.5", - "@walletconnect/utils": "^1.7.5" + "@walletconnect/socket-transport": "^1.7.8", + "@walletconnect/types": "^1.7.8", + "@walletconnect/utils": "^1.7.8" } }, "@walletconnect/crypto": { @@ -20600,12 +20628,12 @@ "integrity": "sha512-4BwqyWy6KpSvkocSaV7WR3BlZfrxLbJSLkg+j7Gl6pTDE+U55lLhJvQaMuDVazXYxcjBsG09k7UlH7cGiUI5vQ==" }, "@walletconnect/http-connection": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@walletconnect/http-connection/-/http-connection-1.7.5.tgz", - "integrity": "sha512-WDy2Y/07c1F107362jel0voeV6QMJuWbwAKNLtxlX8Y9KNzqZAGlHhIZykSWrMjNGwxBaXoqLPmu60uVvodc6A==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@walletconnect/http-connection/-/http-connection-1.7.8.tgz", + "integrity": "sha512-31gjBw46MRU9hFMTNXAqh+f8qpDNzVeV9BJehzVWKiNC3ciL1JCZkbvsY0djwajduE6TB2ujaML0XDXS9HgBRA==", "requires": { - "@walletconnect/types": "^1.7.5", - "@walletconnect/utils": "^1.7.5", + "@walletconnect/types": "^1.7.8", + "@walletconnect/utils": "^1.7.8", "eventemitter3": "4.0.7", "xhr2-cookies": "1.1.0" }, @@ -20618,13 +20646,13 @@ } }, "@walletconnect/iso-crypto": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@walletconnect/iso-crypto/-/iso-crypto-1.7.5.tgz", - "integrity": "sha512-mJdRs2SqAPOLBBqLhU+ZnAh2c8TL2uDuL/ojV4aBzZ0ZHNT7X2zSOjAiixCb3vvH8GAt30OKmiRo3+ChI/9zvA==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@walletconnect/iso-crypto/-/iso-crypto-1.7.8.tgz", + "integrity": "sha512-Qo6qDcMG0Ac+9fpWE0h/oE55NHLk6eM2vlXpWlQDN/me7RZGrkvk+LXsAkQ3UiYPEiPfq4eswcyRWC9AcrAscg==", "requires": { "@walletconnect/crypto": "^1.0.2", - "@walletconnect/types": "^1.7.5", - "@walletconnect/utils": "^1.7.5" + "@walletconnect/types": "^1.7.8", + "@walletconnect/utils": "^1.7.8" } }, "@walletconnect/jsonrpc-types": { @@ -20650,13 +20678,13 @@ "integrity": "sha512-ZtKRio4uCZ1JUF7LIdecmZt7FOLnX72RPSY7aUVu7mj7CSfxDwUn6gBuK6WGtH+NZCldBqDl5DenI5fFSvkKYw==" }, "@walletconnect/qrcode-modal": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@walletconnect/qrcode-modal/-/qrcode-modal-1.7.5.tgz", - "integrity": "sha512-LVq35jc3VMGq1EMcGCObQtEiercMDmUHDnc7A3AmUo0LoAbaPo6c8Hq0zqy2+JhtLmxUhU3ktf+szmCoiUDTUQ==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@walletconnect/qrcode-modal/-/qrcode-modal-1.7.8.tgz", + "integrity": "sha512-LqNJMLWO+ljvoRSdq8tcEslW0imKrrb+ugs3bw4w/jEI1FSJzVeinEsgVpyaMv8wsUcyTcSCXSkXpT1SXHtcpw==", "requires": { - "@walletconnect/browser-utils": "^1.7.5", + "@walletconnect/browser-utils": "^1.7.8", "@walletconnect/mobile-registry": "^1.4.0", - "@walletconnect/types": "^1.7.5", + "@walletconnect/types": "^1.7.8", "copy-to-clipboard": "^3.3.1", "preact": "10.4.1", "qrcode": "1.4.4" @@ -20678,12 +20706,12 @@ "integrity": "sha512-QJzp/S/86sUAgWY6eh5MKYmSfZaRpIlmCJdi5uG4DJlKkZrHEF7ye7gA+VtbVzvTtpM/gRwO2plQuiooIeXjfg==" }, "@walletconnect/socket-transport": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@walletconnect/socket-transport/-/socket-transport-1.7.5.tgz", - "integrity": "sha512-4TYCxrNWb4f5a1NGsALXidr+/6dOiqgVfUQJ4fdP6R7ijL+7jtdiktguU9FIDq5wFXRE+ZdpCpwSAfOt60q/mQ==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@walletconnect/socket-transport/-/socket-transport-1.7.8.tgz", + "integrity": "sha512-bqEjLxfSzG79v2OT7XVOZoyUkg6g3yng0fURrdLusWs42fYHWnrSrIZDejFn8N5PiZk5R2edrggkQ7w0VUUAfw==", "requires": { - "@walletconnect/types": "^1.7.5", - "@walletconnect/utils": "^1.7.5", + "@walletconnect/types": "^1.7.8", + "@walletconnect/utils": "^1.7.8", "ws": "7.5.3" }, "dependencies": { @@ -20696,19 +20724,19 @@ } }, "@walletconnect/types": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-1.7.5.tgz", - "integrity": "sha512-0HvZzxD93et4DdrYgAvclI1BqclkZS7iPWRtbGg3r+PQhRPbOkNypzBy6XH6wflbmr+WBGdmyJvynHsdhcCqUA==" + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-1.7.8.tgz", + "integrity": "sha512-0oSZhKIrtXRJVP1jQ0EDTRtotQY6kggGjDcmm/LLQBKnOZXdPeo0sPkV/7DjT5plT3O7Cjc6JvuXt9WOY0hlCA==" }, "@walletconnect/utils": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-1.7.5.tgz", - "integrity": "sha512-U954rIIA/g/Cmdqy+n3hMY1DDMmXxGs8w/QmrK9b/H5nkQ3e4QicOyynq5g/JTTesN5HZdDTFiyX9r0GSKa+iA==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-1.7.8.tgz", + "integrity": "sha512-DSpfH6Do0TQmdrgzu+SyjVhupVjN0WEMvNWGK9K4VlSmLFpCWfme7qxzrvuxBZ47gDqs1kGWvjyJmviWqvOnAg==", "requires": { - "@walletconnect/browser-utils": "^1.7.5", + "@walletconnect/browser-utils": "^1.7.8", "@walletconnect/encoding": "^1.0.1", "@walletconnect/jsonrpc-utils": "^1.0.0", - "@walletconnect/types": "^1.7.5", + "@walletconnect/types": "^1.7.8", "bn.js": "4.11.8", "js-sha3": "0.8.0", "query-string": "6.13.5" @@ -20737,15 +20765,15 @@ } }, "@walletconnect/web3-provider": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@walletconnect/web3-provider/-/web3-provider-1.7.5.tgz", - "integrity": "sha512-x+UWOTu7jd9qog9NWhaspOmVRDJPnQrgZBscnaSC+x/aAsi52VUrd1GZ9c5UNZFgss41fdx3Z2KhkPeVrlrbuQ==", - "requires": { - "@walletconnect/client": "^1.7.5", - "@walletconnect/http-connection": "^1.7.5", - "@walletconnect/qrcode-modal": "^1.7.5", - "@walletconnect/types": "^1.7.5", - "@walletconnect/utils": "^1.7.5", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@walletconnect/web3-provider/-/web3-provider-1.7.8.tgz", + "integrity": "sha512-2VxGo7KPfQTWRJ+rygt3ok/u04InkVE+H9LBIF/RMUwcwyGf2nsP3CcYZVcg3yYpacgN7bAZCersCEYwU8AeeA==", + "requires": { + "@walletconnect/client": "^1.7.8", + "@walletconnect/http-connection": "^1.7.8", + "@walletconnect/qrcode-modal": "^1.7.8", + "@walletconnect/types": "^1.7.8", + "@walletconnect/utils": "^1.7.8", "web3-provider-engine": "16.0.1" } }, @@ -21248,9 +21276,9 @@ "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==" }, "async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", "requires": { "lodash": "^4.17.14" } @@ -22441,12 +22469,12 @@ } }, "cross-fetch": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-2.2.5.tgz", - "integrity": "sha512-xqYAhQb4NhCJSRym03dwxpP1bYXpK3y7UN83Bo2WFi3x1Zmzn0SL/6xGoPr+gpt4WmNrgCCX3HPysvOwFOW36w==", + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-2.2.6.tgz", + "integrity": "sha512-9JZz+vXCmfKUZ68zAptS7k4Nu8e2qcibe7WVZYps7sAgk5R8GYTc+T1WR0v1rlP9HxgARmOX1UTIJZFytajpNA==", "requires": { - "node-fetch": "2.6.1", - "whatwg-fetch": "2.0.4" + "node-fetch": "^2.6.7", + "whatwg-fetch": "^2.0.4" } }, "cross-spawn": { @@ -23115,7 +23143,6 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "dev": true, "optional": true, "peer": true, "requires": { @@ -23126,7 +23153,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, "optional": true, "peer": true, "requires": { @@ -28167,9 +28193,33 @@ "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==" }, "node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "requires": { + "whatwg-url": "^5.0.0" + }, + "dependencies": { + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } + } }, "node-gyp": { "version": "8.4.1", From e67e57b3ea7597b53fba9c5643b850be8546b865 Mon Sep 17 00:00:00 2001 From: nikitosing Date: Fri, 6 May 2022 10:49:40 +0300 Subject: [PATCH 081/128] Fix internal tx's tile bug --- CHANGELOG.md | 1 + .../templates/internal_transaction/_tile.html.eex | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index af96b8418f7b..7c44b6bcc2f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ### Features ### Fixes +- [#5538](https://github.com/blockscout/blockscout/pull/5538) - Fix internal transaction's tile bug ### Chore - [#5536](https://github.com/blockscout/blockscout/pull/5536) - NPM audit fix diff --git a/apps/block_scout_web/lib/block_scout_web/templates/internal_transaction/_tile.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/internal_transaction/_tile.html.eex index 73b08b37a33f..b7ae6e7f2fd3 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/internal_transaction/_tile.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/internal_transaction/_tile.html.eex @@ -15,9 +15,9 @@
<%= render BlockScoutWeb.TransactionView, "_link.html", transaction_hash: @internal_transaction.transaction_hash %> - <%= @internal_transaction |> BlockScoutWeb.AddressView.address_partial_selector(:from, assigns[:current_address]) |> Keyword.put(:ignore_implementation_name, true) |> BlockScoutWeb.RenderHelpers.render_partial() %> + <%= @internal_transaction |> BlockScoutWeb.AddressView.address_partial_selector(:from, assigns[:current_address]) |> (&(if is_list(&1), do: Keyword.put(&1, :ignore_implementation_name, true), else: &1)).() |> BlockScoutWeb.RenderHelpers.render_partial() %> → - <%= @internal_transaction |> BlockScoutWeb.AddressView.address_partial_selector(:to, assigns[:current_address]) |> Keyword.put(:ignore_implementation_name, true) |> BlockScoutWeb.RenderHelpers.render_partial() %> + <%= @internal_transaction |> BlockScoutWeb.AddressView.address_partial_selector(:to, assigns[:current_address]) |> (&(if is_list(&1), do: Keyword.put(&1, :ignore_implementation_name, true), else: &1)).() |> BlockScoutWeb.RenderHelpers.render_partial() %> From 1c72773e45aad9bd8e9a68638b94d3df6880704c Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Fri, 6 May 2022 18:33:14 +0300 Subject: [PATCH 082/128] Tx page: scroll to tab --- CHANGELOG.md | 1 + .../assets/js/pages/transaction.js | 5 + .../controllers/transaction_controller.ex | 103 +++++++++++++++++- .../templates/transaction/_tabs.html.eex | 6 +- .../show_internal_transactions.html.eex | 1 + .../transaction/show_token_transfers.html.eex | 1 + .../lib/block_scout_web/views/tab_helpers.ex | 19 +++- .../transaction_controller_test.exs | 14 +-- 8 files changed, 129 insertions(+), 21 deletions(-) create mode 100644 apps/block_scout_web/lib/block_scout_web/templates/transaction/show_internal_transactions.html.eex create mode 100644 apps/block_scout_web/lib/block_scout_web/templates/transaction/show_token_transfers.html.eex diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c44b6bcc2f4..cf3408dd81f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## Current ### Features +- [#5540](https://github.com/blockscout/blockscout/pull/5540) - Tx page: scroll to selected tab's data ### Fixes - [#5538](https://github.com/blockscout/blockscout/pull/5538) - Fix internal transaction's tile bug diff --git a/apps/block_scout_web/assets/js/pages/transaction.js b/apps/block_scout_web/assets/js/pages/transaction.js index 410208dfa5b0..dc3def36e617 100644 --- a/apps/block_scout_web/assets/js/pages/transaction.js +++ b/apps/block_scout_web/assets/js/pages/transaction.js @@ -52,6 +52,11 @@ if ($transactionDetailsPage.length) { const store = createStore(reducer) connectElements({ store, elements }) + const pathParts = window.location.pathname.split('/') + if (pathParts.length > 3 && pathParts[3] !== '') { + document.getElementById('transaction-tabs').scrollIntoView() + } + const blocksChannel = socket.channel('blocks:new_block', {}) blocksChannel.join() blocksChannel.on('new_block', (msg) => store.dispatch({ diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_controller.ex index 6ed8cf00b884..68029fe40ca9 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_controller.ex @@ -10,11 +10,28 @@ defmodule BlockScoutWeb.TransactionController do split_list_by_page: 1 ] - alias BlockScoutWeb.{AccessHelpers, Controller, TransactionView} - alias Explorer.Chain + alias BlockScoutWeb.{ + AccessHelpers, + Controller, + TransactionInternalTransactionController, + TransactionTokenTransferController, + TransactionView + } + + alias Explorer.{Chain, Market} alias Explorer.Chain.Cache.Transaction, as: TransactionCache + alias Explorer.ExchangeRates.Token alias Phoenix.View + @necessity_by_association %{ + :block => :optional, + [created_contract_address: :names] => :optional, + [from_address: :names] => :optional, + [to_address: :names] => :optional, + [to_address: :smart_contract] => :optional, + :token_transfers => :optional + } + {:ok, burn_address_hash} = Chain.string_to_address_hash("0x0000000000000000000000000000000000000000") @burn_address_hash burn_address_hash @@ -105,13 +122,89 @@ defmodule BlockScoutWeb.TransactionController do ) end - def show(conn, %{"id" => id}) do + def show(conn, %{"id" => transaction_hash_string, "type" => "JSON"}) do + case Chain.string_to_transaction_hash(transaction_hash_string) do + {:ok, transaction_hash} -> + if Chain.transaction_has_token_transfers?(transaction_hash) do + TransactionTokenTransferController.index(conn, %{ + "transaction_id" => transaction_hash_string, + "type" => "JSON" + }) + else + TransactionInternalTransactionController.index(conn, %{ + "transaction_id" => transaction_hash_string, + "type" => "JSON" + }) + end + + :error -> + set_not_found_view(conn, transaction_hash_string) + end + end + + def show(conn, %{"id" => id} = params) do with {:ok, transaction_hash} <- Chain.string_to_transaction_hash(id), :ok <- Chain.check_transaction_exists(transaction_hash) do if Chain.transaction_has_token_transfers?(transaction_hash) do - redirect(conn, to: AccessHelpers.get_path(conn, :transaction_token_transfer_path, :index, id)) + with {:ok, transaction} <- + Chain.hash_to_transaction( + transaction_hash, + necessity_by_association: @necessity_by_association + ), + {:ok, false} <- AccessHelpers.restricted_access?(to_string(transaction.from_address_hash), params), + {:ok, false} <- AccessHelpers.restricted_access?(to_string(transaction.to_address_hash), params) do + render( + conn, + "show_token_transfers.html", + exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(), + block_height: Chain.block_height(), + current_path: current_path(conn), + show_token_transfers: true, + transaction: transaction + ) + else + :not_found -> + set_not_found_view(conn, id) + + :error -> + set_invalid_view(conn, id) + + {:error, :not_found} -> + set_not_found_view(conn, id) + + {:restricted_access, _} -> + set_not_found_view(conn, id) + end else - redirect(conn, to: AccessHelpers.get_path(conn, :transaction_internal_transaction_path, :index, id)) + with {:ok, transaction} <- + Chain.hash_to_transaction( + transaction_hash, + necessity_by_association: @necessity_by_association + ), + {:ok, false} <- AccessHelpers.restricted_access?(to_string(transaction.from_address_hash), params), + {:ok, false} <- AccessHelpers.restricted_access?(to_string(transaction.to_address_hash), params) do + render( + conn, + "show_internal_transactions.html", + exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(), + current_path: current_path(conn), + block_height: Chain.block_height(), + show_token_transfers: Chain.transaction_has_token_transfers?(transaction_hash), + transaction: transaction + ) + else + :not_found -> + set_not_found_view(conn, id) + + :error -> + set_invalid_view(conn, id) + + {:error, :not_found} -> + set_not_found_view(conn, id) + + {:restricted_access, _} -> + set_not_found_view(conn, id) + end end else :error -> diff --git a/apps/block_scout_web/lib/block_scout_web/templates/transaction/_tabs.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/transaction/_tabs.html.eex index 4d4e2bbfe3e0..284498494291 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/transaction/_tabs.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/transaction/_tabs.html.eex @@ -1,15 +1,15 @@ -
+
<%= if @show_token_transfers do %> <%= link( gettext("Token Transfers"), - class: "card-tab #{tab_status("token-transfers", @conn.request_path)}", + class: "card-tab #{tab_status("token-transfers", @conn.request_path, @show_token_transfers)}", to: AccessHelpers.get_path(@conn, :transaction_token_transfer_path, :index, @transaction) ) %> <% end %> <%= link( gettext("Internal Transactions"), - class: "card-tab #{tab_status("internal-transactions", @conn.request_path)}", + class: "card-tab #{tab_status("internal-transactions", @conn.request_path, @show_token_transfers)}", to: AccessHelpers.get_path(@conn, :transaction_internal_transaction_path, :index, @transaction) ) %> diff --git a/apps/block_scout_web/lib/block_scout_web/templates/transaction/show_internal_transactions.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/transaction/show_internal_transactions.html.eex new file mode 100644 index 000000000000..cbfb925cf8b5 --- /dev/null +++ b/apps/block_scout_web/lib/block_scout_web/templates/transaction/show_internal_transactions.html.eex @@ -0,0 +1 @@ +<%= render BlockScoutWeb.TransactionInternalTransactionView, "index.html", assigns %> \ No newline at end of file diff --git a/apps/block_scout_web/lib/block_scout_web/templates/transaction/show_token_transfers.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/transaction/show_token_transfers.html.eex new file mode 100644 index 000000000000..b524c8e1ffbb --- /dev/null +++ b/apps/block_scout_web/lib/block_scout_web/templates/transaction/show_token_transfers.html.eex @@ -0,0 +1 @@ +<%= render BlockScoutWeb.TransactionTokenTransferView, "index.html", assigns %> \ No newline at end of file diff --git a/apps/block_scout_web/lib/block_scout_web/views/tab_helpers.ex b/apps/block_scout_web/lib/block_scout_web/views/tab_helpers.ex index b3a8ab0c1ba4..26a9f62a8cd7 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/tab_helpers.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/tab_helpers.ex @@ -19,9 +19,26 @@ defmodule BlockScoutWeb.TabHelpers do iex> BlockScoutWeb.TabHelpers.tab_status("token", "/page/0xSom3tH1ng/token_transfer") nil """ - def tab_status(tab_name, request_path) do + def tab_status(tab_name, request_path, show_token_transfers \\ false) do if tab_active?(tab_name, request_path) do "active" + else + case request_path do + "/tx/" <> "0x" <> <<_tx_hash::binary-size(64)>> -> + cond do + tab_name == "token-transfers" && show_token_transfers -> + "active" + + tab_name == "internal-transactions" && !show_token_transfers -> + "active" + + true -> + nil + end + + _ -> + nil + end end end diff --git a/apps/block_scout_web/test/block_scout_web/controllers/transaction_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/transaction_controller_test.exs index 079c961a2e49..2c89c792e404 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/transaction_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/transaction_controller_test.exs @@ -127,21 +127,11 @@ defmodule BlockScoutWeb.TransactionControllerTest do assert html_response(conn, 422) end - test "redirects to transactions/:transaction_id/token-transfers when there are token transfers", %{conn: conn} do + test "no redirect from tx page", %{conn: conn} do transaction = insert(:transaction) - insert(:token_transfer, transaction: transaction) conn = get(conn, transaction_path(BlockScoutWeb.Endpoint, :show, transaction)) - assert redirected_to(conn) =~ transaction_token_transfer_path(BlockScoutWeb.Endpoint, :index, transaction) - end - - test "redirects to transactions/:transaction_id/internal-transactions when there are no token transfers", %{ - conn: conn - } do - transaction = insert(:transaction) - conn = get(conn, transaction_path(BlockScoutWeb.Endpoint, :show, transaction)) - - assert redirected_to(conn) =~ transaction_internal_transaction_path(BlockScoutWeb.Endpoint, :index, transaction) + assert html_response(conn, 200) end end end From 5c611ffc148524957bdf31d2a9a4cd93033c010d Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Mon, 9 May 2022 13:45:01 +0300 Subject: [PATCH 083/128] Increase max_restarts to 1_000 (from 3 by default) for explorer, block_scout_web supervisors --- CHANGELOG.md | 1 + .../assets/js/pages/transaction.js | 7 ++++++- .../lib/block_scout_web/application.ex | 2 +- apps/explorer/lib/explorer/application.ex | 2 +- .../lib/explorer/staking/contract_state.ex | 2 +- .../block/catchup/bound_interval_supervisor.ex | 15 ++++++++++++++- 6 files changed, 24 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf3408dd81f0..27de79c96a30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - [#5538](https://github.com/blockscout/blockscout/pull/5538) - Fix internal transaction's tile bug ### Chore +- [#5543](https://github.com/blockscout/blockscout/pull/5543) - Increase max_restarts to 1_000 (from 3 by default) for explorer, block_scout_web supervisors - [#5536](https://github.com/blockscout/blockscout/pull/5536) - NPM audit fix diff --git a/apps/block_scout_web/assets/js/pages/transaction.js b/apps/block_scout_web/assets/js/pages/transaction.js index dc3def36e617..0c82341909d6 100644 --- a/apps/block_scout_web/assets/js/pages/transaction.js +++ b/apps/block_scout_web/assets/js/pages/transaction.js @@ -53,7 +53,12 @@ if ($transactionDetailsPage.length) { connectElements({ store, elements }) const pathParts = window.location.pathname.split('/') - if (pathParts.length > 3 && pathParts[3] !== '') { + const shouldScroll = pathParts.includes('internal-transactions') || + pathParts.includes('token-transfers') || + pathParts.includes('logs') || + pathParts.includes('token-transfers') || + pathParts.includes('raw-trace') + if (shouldScroll) { document.getElementById('transaction-tabs').scrollIntoView() } diff --git a/apps/block_scout_web/lib/block_scout_web/application.ex b/apps/block_scout_web/lib/block_scout_web/application.ex index 9769d54cfac9..df8904d58624 100644 --- a/apps/block_scout_web/lib/block_scout_web/application.ex +++ b/apps/block_scout_web/lib/block_scout_web/application.ex @@ -26,7 +26,7 @@ defmodule BlockScoutWeb.Application do {BlocksIndexedCounter, name: BlocksIndexedCounter} ] - opts = [strategy: :one_for_one, name: BlockScoutWeb.Supervisor] + opts = [strategy: :one_for_one, name: BlockScoutWeb.Supervisor, max_restarts: 1_000] Supervisor.start_link(children, opts) end diff --git a/apps/explorer/lib/explorer/application.ex b/apps/explorer/lib/explorer/application.ex index 8fa1d77db10b..e01d2531ae3d 100644 --- a/apps/explorer/lib/explorer/application.ex +++ b/apps/explorer/lib/explorer/application.ex @@ -68,7 +68,7 @@ defmodule Explorer.Application do children = base_children ++ configurable_children() - opts = [strategy: :one_for_one, name: Explorer.Supervisor] + opts = [strategy: :one_for_one, name: Explorer.Supervisor, max_restarts: 1_000] Supervisor.start_link(children, opts) end diff --git a/apps/explorer/lib/explorer/staking/contract_state.ex b/apps/explorer/lib/explorer/staking/contract_state.ex index ab1ede8f88a8..1ed77701737b 100644 --- a/apps/explorer/lib/explorer/staking/contract_state.ex +++ b/apps/explorer/lib/explorer/staking/contract_state.ex @@ -163,7 +163,7 @@ defmodule Explorer.Staking.ContractState do contracts: %{ staking: staking_contract_address } - }, {:continue, []}} + }, {:stop, "The archive node is unavailable"}} end end diff --git a/apps/indexer/lib/indexer/block/catchup/bound_interval_supervisor.ex b/apps/indexer/lib/indexer/block/catchup/bound_interval_supervisor.ex index ffed2919a9ff..181b8e49a75a 100644 --- a/apps/indexer/lib/indexer/block/catchup/bound_interval_supervisor.ex +++ b/apps/indexer/lib/indexer/block/catchup/bound_interval_supervisor.ex @@ -268,7 +268,20 @@ defmodule Indexer.Block.Catchup.BoundIntervalSupervisor do task: %Task{ref: ref} } = state ) do - Logger.info("Index had to catch up, but the but request is timing out, so retrying immediately.") + Logger.info("Index had to catch up, but the request is timing out, so retrying immediately.") + + send(self(), :catchup_index) + + {:noreply, %__MODULE__{state | task: nil}} + end + + def handle_info( + {_ref1, {:error, :enetunreach}}, + %__MODULE__{ + task: _ + } = state + ) do + Logger.info("Index had to catch up, but the request is timing out, so retrying immediately.") send(self(), :catchup_index) From 67dd49a1010d46181b384f4289941e4274d07092 Mon Sep 17 00:00:00 2001 From: nikitosing Date: Tue, 17 May 2022 11:41:43 +0300 Subject: [PATCH 084/128] Add fallback clauses to string_to_*_hash functions --- CHANGELOG.md | 1 + apps/explorer/lib/explorer/chain.ex | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 27de79c96a30..501a38543bda 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - [#5540](https://github.com/blockscout/blockscout/pull/5540) - Tx page: scroll to selected tab's data ### Fixes +- [#5564](https://github.com/blockscout/blockscout/pull/5564) - Add fallback clauses to `string_to_..._hash` functions - [#5538](https://github.com/blockscout/blockscout/pull/5538) - Fix internal transaction's tile bug ### Chore diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index 44dc20968d74..10968e6c2d35 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -3403,6 +3403,8 @@ defmodule Explorer.Chain do Hash.Address.cast(string) end + def string_to_address_hash(_), do: :error + @doc """ The `string` must start with `0x`, then is converted to an integer and then to `t:Explorer.Chain.Hash.t/0`. @@ -3428,6 +3430,8 @@ defmodule Explorer.Chain do Hash.Full.cast(string) end + def string_to_block_hash(_), do: :error + @doc """ The `string` must start with `0x`, then is converted to an integer and then to `t:Explorer.Chain.Hash.t/0`. @@ -3453,6 +3457,8 @@ defmodule Explorer.Chain do Hash.Full.cast(string) end + def string_to_transaction_hash(_), do: :error + @doc """ `t:Explorer.Chain.InternalTransaction/0`s in `t:Explorer.Chain.Transaction.t/0` with `hash`. From c5ef7c1c7e60c0f66b7ed8e48188250ef70d2f55 Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Tue, 17 May 2022 18:29:44 +0300 Subject: [PATCH 085/128] Sanitize token name and symbol before insert, disaply --- CHANGELOG.md | 1 + .../assets/__tests__/lib/autocomplete.js | 31 +++++++++++++ .../assets/__tests__/lib/utils.js | 12 +++++ .../assets/js/lib/autocomplete.js | 40 +++++++++-------- apps/block_scout_web/assets/js/lib/try_api.js | 15 +------ apps/block_scout_web/assets/js/lib/utils.js | 12 +++++ .../lib/block_scout_web/views/search_view.ex | 7 ++- apps/block_scout_web/mix.exs | 2 +- .../views/search_view_test.exs | 44 +++++++++++++++++++ apps/explorer/lib/explorer/chain/token.ex | 20 +++++++++ apps/explorer/mix.exs | 1 + mix.lock | 8 ++-- 12 files changed, 155 insertions(+), 38 deletions(-) create mode 100644 apps/block_scout_web/assets/__tests__/lib/autocomplete.js create mode 100644 apps/block_scout_web/assets/__tests__/lib/utils.js create mode 100644 apps/block_scout_web/test/block_scout_web/views/search_view_test.exs diff --git a/CHANGELOG.md b/CHANGELOG.md index 501a38543bda..446f018397b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - [#5540](https://github.com/blockscout/blockscout/pull/5540) - Tx page: scroll to selected tab's data ### Fixes +- [#5567](https://github.com/blockscout/blockscout/pull/5567) - Sanitize token name and symbol before insert into DB, display in the application - [#5564](https://github.com/blockscout/blockscout/pull/5564) - Add fallback clauses to `string_to_..._hash` functions - [#5538](https://github.com/blockscout/blockscout/pull/5538) - Fix internal transaction's tile bug diff --git a/apps/block_scout_web/assets/__tests__/lib/autocomplete.js b/apps/block_scout_web/assets/__tests__/lib/autocomplete.js new file mode 100644 index 000000000000..877474c92797 --- /dev/null +++ b/apps/block_scout_web/assets/__tests__/lib/autocomplete.js @@ -0,0 +1,31 @@ +/** + * @jest-environment jsdom + */ + + import { searchEngine } from '../../js/lib/autocomplete' + + test('searchEngine', () => { + expect(searchEngine('qwe', { + 'name': 'Test', + 'symbol': 'TST', + 'address_hash': '0x000', + 'tx_hash': '0x000', + 'block_hash': '0x000' + })).toEqual(undefined) + + expect(searchEngine('tes', { + 'name': 'Test', + 'symbol': 'TST', + 'address_hash': '0x000', + 'tx_hash': '0x000', + 'block_hash': '0x000' + })).toEqual('
0x000
Test (TST)
') + + expect(searchEngine('qwe', { + 'name': 'qwe1\'">