banano-nft-crawler
Advanced tools
Comparing version 1.1.2 to 1.1.3
@@ -55,2 +55,4 @@ "use strict"; | ||
}); | ||
assetCrawler.head = _mintBlock.hash; | ||
assetCrawler.headHeight = parseInt(_mintBlock.height); | ||
return [2 /*return*/, true]; | ||
@@ -68,2 +70,4 @@ } | ||
}); | ||
assetCrawler.head = _mintBlock.hash; | ||
assetCrawler.headHeight = parseInt(_mintBlock.height); | ||
return [2 /*return*/, true]; | ||
@@ -70,0 +74,0 @@ } |
@@ -76,2 +76,4 @@ "use strict"; | ||
assetCrawler.traceLength += BigInt(1); | ||
assetCrawler.head = nanoBlock.hash; | ||
assetCrawler.headHeight = parseInt(nanoBlock.height); | ||
assetBlock = toAssetBlock(assetCrawler, nanoBlock); | ||
@@ -78,0 +80,0 @@ if (assetBlock === undefined) { |
@@ -43,5 +43,5 @@ "use strict"; | ||
return __awaiter(this, void 0, void 0, function () { | ||
var sendBlockHash, sender, recipient, receiveBlock; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
var sendBlockHash, sender, recipient, _a, success, block; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
@@ -58,9 +58,14 @@ sendBlockHash = assetCrawler.frontier.nanoBlock.hash; | ||
case 1: | ||
receiveBlock = _a.sent(); | ||
_a = _b.sent(), success = _a.success, block = _a.block; | ||
// guards | ||
if (typeof receiveBlock === 'undefined') { | ||
if (typeof block === 'undefined') { | ||
return [2 /*return*/, false]; | ||
} | ||
assetCrawler.traceLength += BigInt(1); | ||
if (receiveBlock.subtype === 'receive' && receiveBlock.link === sendBlockHash) { | ||
assetCrawler.head = block.hash; | ||
assetCrawler.headHeight = parseInt(block.height); | ||
if (!success) { | ||
return [2 /*return*/, false]; | ||
} | ||
if (block.subtype === 'receive' && block.link === sendBlockHash) { | ||
assetCrawler.assetChain.push({ | ||
@@ -72,3 +77,3 @@ state: 'owned', | ||
locked: false, | ||
nanoBlock: receiveBlock, | ||
nanoBlock: block, | ||
traceLength: assetCrawler.traceLength | ||
@@ -75,0 +80,0 @@ }); |
@@ -84,2 +84,4 @@ "use strict"; | ||
}); | ||
assetCrawler.head = nextBlock.hash; | ||
assetCrawler.headHeight = parseInt(nextBlock.height); | ||
} | ||
@@ -115,2 +117,4 @@ else { | ||
}); | ||
assetCrawler.head = sendAtomicSwap.nanoBlock.hash; | ||
assetCrawler.headHeight = parseInt(sendAtomicSwap.nanoBlock.height); | ||
} | ||
@@ -117,0 +121,0 @@ return [2 /*return*/, true]; |
@@ -98,2 +98,4 @@ "use strict"; | ||
}); | ||
assetCrawler.head = receiveBlock.hash; | ||
assetCrawler.headHeight = parseInt(receiveBlock.height); | ||
} | ||
@@ -120,2 +122,4 @@ else { | ||
}); | ||
assetCrawler.head = sendAtomicSwap.nanoBlock.hash; | ||
assetCrawler.headHeight = parseInt(sendAtomicSwap.nanoBlock.height); | ||
} | ||
@@ -122,0 +126,0 @@ return [2 /*return*/, true]; |
@@ -57,2 +57,4 @@ "use strict"; | ||
assetCrawler.assetChain.push(frontier); | ||
assetCrawler.head = sendAtomicSwapBlock.nanoBlock.hash; | ||
assetCrawler.headHeight = parseInt(sendAtomicSwapBlock.nanoBlock.height); | ||
return [2 /*return*/, true]; | ||
@@ -59,0 +61,0 @@ }); |
import { INanoBlock } from "nano-account-crawler/dist/nano-interfaces"; | ||
import { IAssetBlock } from "./interfaces/asset-block"; | ||
import { IAtomicSwapConditions } from "./interfaces/atomic-swap-conditions"; | ||
import { TBlockHash } from "./types/banano"; | ||
import { NanoNode } from 'nano-account-crawler/dist/nano-node'; | ||
@@ -8,2 +9,4 @@ export declare class AssetCrawler { | ||
private _assetRepresentative; | ||
private _head; | ||
private _headHeight; | ||
private _metadataRepresentative; | ||
@@ -20,2 +23,4 @@ private _issuer; | ||
crawl(nanoNode: NanoNode, maxTraceLength?: bigint): Promise<void>; | ||
initFromCache(assetRepresentative: string, assetChain: IAssetBlock[], initialTraceLength?: bigint): void; | ||
crawlFromFrontier(nanoNode: NanoNode, maxTraceLength?: bigint): Promise<void>; | ||
private crawlStep; | ||
@@ -28,2 +33,6 @@ currentAtomicSwapConditions(): IAtomicSwapConditions | undefined; | ||
get assetRepresentative(): string; | ||
get head(): (undefined | TBlockHash); | ||
set head(value: TBlockHash); | ||
get headHeight(): (undefined | number); | ||
set headHeight(value: number); | ||
get issuer(): string; | ||
@@ -30,0 +39,0 @@ get metadataRepresentative(): string; |
@@ -72,3 +72,2 @@ "use strict"; | ||
return __awaiter(this, void 0, void 0, function () { | ||
var newStep; | ||
return __generator(this, function (_a) { | ||
@@ -85,15 +84,35 @@ switch (_a.label) { | ||
_a.label = 2; | ||
case 2: | ||
case 2: return [4 /*yield*/, this.crawlFromFrontier(nanoNode, maxTraceLength)]; | ||
case 3: | ||
_a.sent(); | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
}); | ||
}; | ||
AssetCrawler.prototype.initFromCache = function (assetRepresentative, assetChain, initialTraceLength) { | ||
if (initialTraceLength === void 0) { initialTraceLength = undefined; } | ||
this._assetRepresentative = assetRepresentative; | ||
this._assetChain = assetChain; | ||
this._traceLength = initialTraceLength || this._traceLength; | ||
}; | ||
AssetCrawler.prototype.crawlFromFrontier = function (nanoNode, maxTraceLength) { | ||
if (maxTraceLength === void 0) { maxTraceLength = constants_1.MAX_TRACE_LENGTH; } | ||
return __awaiter(this, void 0, void 0, function () { | ||
var newStep; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
newStep = true; | ||
_a.label = 3; | ||
case 3: | ||
if (!newStep) return [3 /*break*/, 5]; | ||
_a.label = 1; | ||
case 1: | ||
if (!newStep) return [3 /*break*/, 3]; | ||
return [4 /*yield*/, this.crawlStep(nanoNode).catch(function (error) { throw (error); })]; | ||
case 4: | ||
case 2: | ||
newStep = _a.sent(); | ||
if (this._traceLength >= maxTraceLength) { | ||
return [3 /*break*/, 5]; | ||
return [3 /*break*/, 3]; | ||
} | ||
return [3 /*break*/, 3]; | ||
case 5: return [2 /*return*/]; | ||
return [3 /*break*/, 1]; | ||
case 3: return [2 /*return*/]; | ||
} | ||
@@ -166,2 +185,22 @@ }); | ||
}); | ||
Object.defineProperty(AssetCrawler.prototype, "head", { | ||
get: function () { | ||
return this._head; | ||
}, | ||
set: function (value) { | ||
this._head = value; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(AssetCrawler.prototype, "headHeight", { | ||
get: function () { | ||
return this._headHeight; | ||
}, | ||
set: function (value) { | ||
this._headHeight = value; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(AssetCrawler.prototype, "issuer", { | ||
@@ -168,0 +207,0 @@ get: function () { |
import { INanoBlock } from "nano-account-crawler/dist/nano-interfaces"; | ||
import { NanoNode } from "nano-account-crawler/dist/nano-node"; | ||
export declare function findReceiveBlock(nanoNode: NanoNode, senderAccount: string, sendHash: string, receiverAccount: string): Promise<(INanoBlock | undefined)>; | ||
export declare function findReceiveBlock(nanoNode: NanoNode, senderAccount: string, sendHash: string, receiverAccount: string): Promise<({ | ||
success: boolean; | ||
block: INanoBlock | undefined; | ||
})>; |
@@ -51,3 +51,3 @@ "use strict"; | ||
return __awaiter(this, void 0, void 0, function () { | ||
var nanoBackwardIterable, nanoBackwardIterable_1, nanoBackwardIterable_1_1, block, e_1_1, error_1; | ||
var nanoBackwardIterable, headBlock, nanoBackwardIterable_1, nanoBackwardIterable_1_1, block, e_1_1, error_1; | ||
return __generator(this, function (_b) { | ||
@@ -57,6 +57,7 @@ switch (_b.label) { | ||
_b.trys.push([0, 14, , 15]); | ||
nanoBackwardIterable = new nano_account_backward_crawler_1.NanoAccountBackwardCrawler(nanoNode, receiverAccount, undefined, [senderAccount]); | ||
nanoBackwardIterable = new nano_account_backward_crawler_1.NanoAccountBackwardCrawler(nanoNode, receiverAccount, undefined); | ||
return [4 /*yield*/, nanoBackwardIterable.initialize()]; | ||
case 1: | ||
_b.sent(); | ||
headBlock = void 0; | ||
_b.label = 2; | ||
@@ -71,4 +72,5 @@ case 2: | ||
block = nanoBackwardIterable_1_1.value; | ||
headBlock = headBlock || block; | ||
if (block.type === 'state' && block.subtype === 'receive' && block.link === sendHash) { | ||
return [2 /*return*/, block]; | ||
return [2 /*return*/, { success: true, block: block }]; | ||
} | ||
@@ -94,3 +96,3 @@ _b.label = 5; | ||
case 12: return [7 /*endfinally*/]; | ||
case 13: return [2 /*return*/, undefined]; | ||
case 13: return [2 /*return*/, { success: false, block: headBlock }]; | ||
case 14: | ||
@@ -97,0 +99,0 @@ error_1 = _b.sent(); |
import { INanoBlock } from "nano-account-crawler/dist/nano-interfaces"; | ||
import { NanoNode } from 'nano-account-crawler/dist/nano-node'; | ||
import { TBlockHash } from "./types/banano"; | ||
export declare class MintBlocksCrawler { | ||
private _hasLimitedSupply; | ||
private _head; | ||
private _headHeight; | ||
private _ipfsCID; | ||
@@ -9,8 +12,16 @@ private _issuer; | ||
private _nftSupplyBlockHash; | ||
private _nftSupplyBlockHeight; | ||
private _maxSupply; | ||
private _metadataRepresentative; | ||
private _mintBlocks; | ||
private _mintBlockCount; | ||
private _version; | ||
private _finishedSupply; | ||
private _cachedData; | ||
constructor(issuer: string, nftSupplyBlockHash: string); | ||
initFromCache(nftSupplyBlockHeight: bigint, mintBlockCount: bigint, version: string, maxSupply: bigint, metadataRepresentative: string): void; | ||
private cachedCrawlData; | ||
crawl(nanoNode: NanoNode, maxRpcIterations?: number): Promise<void>; | ||
crawlFromFrontier(nanoNode: NanoNode, frontier: TBlockHash, maxRpcIterations?: number): Promise<void>; | ||
addMintBlock(block: INanoBlock): void; | ||
get nftSupplyBlock(): INanoBlock; | ||
@@ -22,3 +33,8 @@ get mintBlocks(): INanoBlock[]; | ||
get hasLimitedSupply(): boolean; | ||
get finishedSupply(): boolean; | ||
get mintBlockCount(): bigint; | ||
get head(): (undefined | TBlockHash); | ||
get headHeight(): (undefined | number); | ||
private parseSupplyBlock; | ||
private cachedSupplyBlock; | ||
private parseFinishSupplyBlock; | ||
@@ -25,0 +41,0 @@ private parseFirstMint; |
@@ -55,5 +55,20 @@ "use strict"; | ||
function MintBlocksCrawler(issuer, nftSupplyBlockHash) { | ||
this._cachedData = false; | ||
this._issuer = issuer; | ||
this._nftSupplyBlockHash = nftSupplyBlockHash; | ||
this._finishedSupply = false; | ||
this._mintBlocks = []; | ||
} | ||
MintBlocksCrawler.prototype.initFromCache = function (nftSupplyBlockHeight, mintBlockCount, version, maxSupply, metadataRepresentative) { | ||
this._nftSupplyBlockHeight = nftSupplyBlockHeight; | ||
this._mintBlockCount = mintBlockCount; | ||
this._version = version; | ||
this._maxSupply = maxSupply; | ||
this._hasLimitedSupply = this._maxSupply > BigInt("0"); | ||
this._finishedSupply = this.supplyExceeded(); | ||
this._metadataRepresentative = metadataRepresentative; | ||
}; | ||
MintBlocksCrawler.prototype.cachedCrawlData = function () { | ||
return typeof (this._nftSupplyBlockHeight) == 'bigint' && typeof (this._mintBlockCount) == 'bigint'; | ||
}; | ||
MintBlocksCrawler.prototype.crawl = function (nanoNode, maxRpcIterations) { | ||
@@ -67,2 +82,5 @@ var e_1, _a; | ||
case 0: | ||
if (this._finishedSupply) { | ||
return [2 /*return*/]; | ||
} | ||
banCrawler = new nano_account_forward_crawler_1.NanoAccountForwardCrawler(nanoNode, this._issuer, this._nftSupplyBlockHash); | ||
@@ -74,2 +92,3 @@ return [4 /*yield*/, banCrawler.initialize()]; | ||
this._mintBlocks = []; | ||
this._mintBlockCount = BigInt("0"); | ||
blockOffset = 0; | ||
@@ -91,2 +110,3 @@ _b.label = 2; | ||
else if (this.parseFinishSupplyBlock(block)) { | ||
this._finishedSupply = true; | ||
return [3 /*break*/, 6]; | ||
@@ -96,8 +116,23 @@ } | ||
if (block.representative === constants_1.CANCEL_SUPPLY_REPRESENTATIVE) { | ||
this._finishedSupply = true; | ||
return [3 /*break*/, 6]; | ||
} | ||
else { | ||
try { | ||
(0, validate_mint_block_1.validateMintBlock)(block); | ||
this.parseFirstMint(block); | ||
this._mintBlocks.push(block); | ||
this._mintBlockCount++; | ||
} | ||
catch (error) { | ||
if (error.message.match(/^MintBlockError\:/)) { | ||
this._finishedSupply = true; | ||
return [3 /*break*/, 6]; | ||
} | ||
else { | ||
throw error; | ||
} | ||
} | ||
} | ||
; | ||
(0, validate_mint_block_1.validateMintBlock)(block); | ||
this.parseFirstMint(block); | ||
this._mintBlocks.push(block); | ||
} | ||
@@ -107,3 +142,3 @@ else if (blockOffset > 1 && block.representative === this._metadataRepresentative) { | ||
(0, validate_mint_block_1.validateMintBlock)(block); | ||
this._mintBlocks.push(block); | ||
this.addMintBlock(block); | ||
} | ||
@@ -117,2 +152,3 @@ catch (error) { | ||
if (this.supplyExceeded()) { | ||
this._finishedSupply = true; | ||
return [3 /*break*/, 6]; | ||
@@ -145,2 +181,85 @@ } | ||
}; | ||
MintBlocksCrawler.prototype.crawlFromFrontier = function (nanoNode, frontier, maxRpcIterations) { | ||
var e_2, _a; | ||
if (maxRpcIterations === void 0) { maxRpcIterations = constants_1.MAX_RPC_ITERATIONS; } | ||
return __awaiter(this, void 0, void 0, function () { | ||
var banCrawler, banCrawler_2, banCrawler_2_1, block, e_2_1; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
if (this._finishedSupply) { | ||
return [2 /*return*/]; | ||
} | ||
if (!this.cachedSupplyBlock()) { | ||
throw Error("CacheError: crawlFromFrontier: Supply block not cached"); | ||
} | ||
if (!this.cachedCrawlData()) { | ||
throw Error("CacheError: crawlFromFrontier: No cached crawl data"); | ||
} | ||
if (typeof (this._metadataRepresentative) !== 'string' && this._metadataRepresentative.match(constants_1.ADDRESS_PATTERN)) { | ||
throw Error("CacheError: crawlFromFrontier: No cached metadata representative"); | ||
} | ||
banCrawler = new nano_account_forward_crawler_1.NanoAccountForwardCrawler(nanoNode, this._issuer, frontier, "1"); | ||
return [4 /*yield*/, banCrawler.initialize()]; | ||
case 1: | ||
_b.sent(); | ||
banCrawler.maxRpcIterations = maxRpcIterations; | ||
_b.label = 2; | ||
case 2: | ||
_b.trys.push([2, 7, 8, 13]); | ||
banCrawler_2 = __asyncValues(banCrawler); | ||
_b.label = 3; | ||
case 3: return [4 /*yield*/, banCrawler_2.next()]; | ||
case 4: | ||
if (!(banCrawler_2_1 = _b.sent(), !banCrawler_2_1.done)) return [3 /*break*/, 6]; | ||
block = banCrawler_2_1.value; | ||
if (this.parseFinishSupplyBlock(block)) { | ||
this._finishedSupply = true; | ||
return [3 /*break*/, 6]; | ||
} | ||
else if (block.representative === this._metadataRepresentative) { | ||
try { | ||
(0, validate_mint_block_1.validateMintBlock)(block); | ||
this.addMintBlock(block); | ||
} | ||
catch (error) { | ||
if (!error.message.match(/^MintBlockError\:/)) { | ||
throw error; | ||
} | ||
} | ||
} | ||
if (this.supplyExceeded()) { | ||
this._finishedSupply = true; | ||
return [3 /*break*/, 6]; | ||
} | ||
_b.label = 5; | ||
case 5: return [3 /*break*/, 3]; | ||
case 6: return [3 /*break*/, 13]; | ||
case 7: | ||
e_2_1 = _b.sent(); | ||
e_2 = { error: e_2_1 }; | ||
return [3 /*break*/, 13]; | ||
case 8: | ||
_b.trys.push([8, , 11, 12]); | ||
if (!(banCrawler_2_1 && !banCrawler_2_1.done && (_a = banCrawler_2.return))) return [3 /*break*/, 10]; | ||
return [4 /*yield*/, _a.call(banCrawler_2)]; | ||
case 9: | ||
_b.sent(); | ||
_b.label = 10; | ||
case 10: return [3 /*break*/, 12]; | ||
case 11: | ||
if (e_2) throw e_2.error; | ||
return [7 /*endfinally*/]; | ||
case 12: return [7 /*endfinally*/]; | ||
case 13: return [2 /*return*/]; | ||
} | ||
}); | ||
}); | ||
}; | ||
MintBlocksCrawler.prototype.addMintBlock = function (block) { | ||
this._mintBlocks.push(block); | ||
this._mintBlockCount++; | ||
this._head = block.hash; | ||
this._headHeight = parseInt(block.height); | ||
}; | ||
Object.defineProperty(MintBlocksCrawler.prototype, "nftSupplyBlock", { | ||
@@ -188,2 +307,30 @@ get: function () { | ||
}); | ||
Object.defineProperty(MintBlocksCrawler.prototype, "finishedSupply", { | ||
get: function () { | ||
return this._finishedSupply; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(MintBlocksCrawler.prototype, "mintBlockCount", { | ||
get: function () { | ||
return this._mintBlockCount; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(MintBlocksCrawler.prototype, "head", { | ||
get: function () { | ||
return this._head; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(MintBlocksCrawler.prototype, "headHeight", { | ||
get: function () { | ||
return this._headHeight; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
MintBlocksCrawler.prototype.parseSupplyBlock = function (block) { | ||
@@ -198,5 +345,9 @@ var supplyData = (0, supply_1.parseSupplyRepresentative)(block.representative); | ||
this._nftSupplyBlock = block; | ||
this._nftSupplyBlockHeight = BigInt(block.height); | ||
this._hasLimitedSupply = this._maxSupply > BigInt("0"); | ||
return true; | ||
}; | ||
MintBlocksCrawler.prototype.cachedSupplyBlock = function () { | ||
return constants_1.META_PROTOCOL_SUPPORTED_VERSIONS.includes(this._version) && typeof (this._maxSupply) === 'bigint' && typeof (this._nftSupplyBlockHeight) === 'bigint' && typeof (this._hasLimitedSupply) == 'boolean'; | ||
}; | ||
MintBlocksCrawler.prototype.parseFinishSupplyBlock = function (block) { | ||
@@ -208,3 +359,3 @@ var finishSupplyData = (0, supply_1.parseFinishSupplyRepresentative)(block.representative); | ||
var supplyBlockHeight = finishSupplyData.supplyBlockHeight; | ||
return supplyBlockHeight === BigInt(this._nftSupplyBlock.height); | ||
return supplyBlockHeight === this._nftSupplyBlockHeight; | ||
}; | ||
@@ -216,3 +367,3 @@ MintBlocksCrawler.prototype.parseFirstMint = function (block) { | ||
MintBlocksCrawler.prototype.supplyExceeded = function () { | ||
return this._hasLimitedSupply && BigInt(this._mintBlocks.length) >= this._maxSupply; | ||
return this._hasLimitedSupply && this._mintBlockCount >= this._maxSupply; | ||
}; | ||
@@ -219,0 +370,0 @@ return MintBlocksCrawler; |
@@ -5,4 +5,5 @@ import { INanoBlock } from "nano-account-crawler/dist/nano-interfaces"; | ||
export declare class SupplyBlocksCrawler { | ||
private _head; | ||
private _headHeight; | ||
private _issuer; | ||
private _head; | ||
private _offset; | ||
@@ -16,2 +17,5 @@ ignoreMetadataRepresentatives: TAccount[]; | ||
private validateSupplyBlock; | ||
private validateSupplyRepresentative; | ||
get head(): (undefined | TBlockHash); | ||
get headHeight(): (undefined | number); | ||
} |
@@ -93,3 +93,9 @@ "use strict"; | ||
this._head = frontierCheckedBlock.hash; | ||
this._offset = "1"; | ||
this._headHeight = parseInt(frontierCheckedBlock.height); | ||
if (this.validateSupplyRepresentative(frontierCheckedBlock.representative)) { | ||
this._offset = "-1"; | ||
} | ||
else { | ||
this._offset = "0"; | ||
} | ||
_b.label = 5; | ||
@@ -149,4 +155,7 @@ case 5: return [3 /*break*/, 3]; | ||
} | ||
return this.validateSupplyRepresentative(block.representative); | ||
}; | ||
SupplyBlocksCrawler.prototype.validateSupplyRepresentative = function (representative) { | ||
// Check if representative is a parsable supply_representative with a supported version | ||
var supplyData = (0, supply_1.parseSupplyRepresentative)(block.representative); | ||
var supplyData = (0, supply_1.parseSupplyRepresentative)(representative); | ||
if (!supplyData) { | ||
@@ -160,2 +169,16 @@ return false; | ||
}; | ||
Object.defineProperty(SupplyBlocksCrawler.prototype, "head", { | ||
get: function () { | ||
return this._head; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(SupplyBlocksCrawler.prototype, "headHeight", { | ||
get: function () { | ||
return this._headHeight; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
return SupplyBlocksCrawler; | ||
@@ -162,0 +185,0 @@ }()); |
{ | ||
"name": "banano-nft-crawler", | ||
"version": "1.1.2", | ||
"version": "1.1.3", | ||
"description": "Library for crawling across the Banano ledger to trace NFTs.", | ||
@@ -5,0 +5,0 @@ "files": [ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
343798
4911