Add stylesheets to dynamic targets.

Add stylesheets to dynamic targets.

#!/usr/bin/env jq
# This is a collection of filters for `jq`, intended to manipulate JSON objects
# into JSON representing a website index, for further processing in a template.

# Convert "truthy" value to actual boolean.
def bool:
    [. == (null,false,0,{},[])] | any | not
;

# Generate this object and all its children.
def all_children:
    ., recurse(.contents[]?)
;

# To remove an object, we first mark it for removal, then actually remove it
# later. It would be nicer if we could just do `all_children ... |= empty`,
# which works in some cases but not all. I suppose it has to do with changing
# objects as we are iterating over them.
def mark:
    .remove = true
;

# Remove all objects marked for removal.
def remove_marked:
    if .remove == true
    then empty
    else (.contents // empty) |= map(remove_marked)
    end
;

# Wrap an object in other objects so that the original object exists at a
# particular "path". Like `{} | setpath(["a","b"], …)`, but instead of making
# objects like `{"a":{"b":…}}`, this makes objects like `{"name":"a",
# "contents":[{"name":"b",…}]}`.
def tree($path):
    if ($path | length) <= 1
    then .name = $path[0]
    else { "name": $path[0], "contents": [ tree($path[1:]) ] }
    end
;

# Merge an array of page objects into a single page object.
def merge:
    map(to_entries) | add | group_by(.key) | map(
        { "key": (.[0].key)
        , "value": (
            if .[0].key == "contents"
            then [ .[].value ] | add | group_by(.name) | map(merge)
            elif [ .[].value == .[0].value ] | all
            then .[0].value
            else error("can't merge incompatible values")
            end
        ) }
    ) | from_entries
;

# Add paths to each object, that is, the names of the ancestors.
def directory:
    def f($d): .directory = $d | .name as $n | .contents[]? |= f($d+[$n]);
    f([])
;

# Every leaf node gets a basename, eg name without extension.
def basename:
    (all_children | select(has("contents") | not)) |= (
        .basename = (.name | sub(".([A-z]*)$";""))
    )
;

# Any Markdown page gets a link to its HTML page.
def link:
    (all_children | select(has("directory") and has("basename") and (.name | test(".(md|markdown)$";"i")))) |= (
        .link = ((.directory + [.basename + ".html"]) | join("/") | ltrimstr("./"))
    )
;

# Front matter is the page to be associated with the enclosing directory rather
# than itself.
def frontmatter:
    (all_children | select(has("contents"))) |= (
        (.frontmatter = [.contents[] | select(.meta.frontmatter | bool)][0]) |
        (.contents = .contents - [.frontmatter])
    )
;

# Drafts can be excluded from being uploaded and included in the table of
# contents. To not count as a draft, a document should be explicitly marked as
# "publish" in the metadata.
def explicit_publish:
    def publish: has("contents") or .external or .meta.publish | bool;
    (( all_children | select(publish | not)) |= mark) | remove_marked
;

# Sort content first according to sort order in metadata.
def sort_content:
    (all_children | select(has("contents")) | .contents) |= (
        sort_by(.meta.sort // .meta.title // .name)
    )
;

# Add a note that tells us whether this has only children who have no more
# subchildren.
def annotate_leaves:
    (all_children | select(has("contents"))) |= (
        .only_leaves = (.contents | all(has("contents") | not))
    )
;

# Combines the given stream of JSON objects by merging them, and performs the
# given operations to turn it into a proper index.
def index:
    merge
    | directory
    | basename
    | link
    | explicit_publish
    | frontmatter
    | sort_content
    | annotate_leaves
;

# Get publishable targets from an index, as an object containing the names of
# the relevant Makefile recipes.
def targets($dest):
    def in_dir($dir; $file):
        $dir + [$file] | join("/") | ltrimstr("./") | ($dest + "/" + .)
    ;
    [ all_children
        | ., (.frontmatter // empty)
        | select(has("directory") and has("basename") and (has("external") | not))
        | {"target": "pdf-targets", "name": in_dir(.directory; .basename + ".pdf")}
        , {"target": "html-targets", "name": in_dir(.directory; .basename + ".html")}
        , {"target": "external-targets", "name": in_dir(.directory; .targets?[])}
        , {"target": "external-targets", "name": in_dir(["."]; (.meta.style // empty) + ".css")}
    ]
    | group_by(.target)
    | map({(.[0].target): map(.name)})
    | add
;

# Turn a target object into makefile recipes.
def as_makefile:
    . + {".PHONY": keys} | to_entries[] | (.key + ": " + (.value | join(" ")))
;

#!/usr/bin/env jq
# This is a collection of filters for `jq`, intended to manipulate JSON objects
# into JSON representing a website index, for further processing in a template.

# Convert "truthy" value to actual boolean.
def bool:
    [. == (null,false,0,{},[])] | any | not
;

# Generate this object and all its children.
def all_children:
    ., recurse(.contents[]?)
;

# To remove an object, we first mark it for removal, then actually remove it
# later. It would be nicer if we could just do `all_children ... |= empty`,
# which works in some cases but not all. I suppose it has to do with changing
# objects as we are iterating over them.
def mark:
    .remove = true
;

# Remove all objects marked for removal.
def remove_marked:
    if .remove == true
    then empty
    else (.contents // empty) |= map(remove_marked)
    end
;

# Wrap an object in other objects so that the original object exists at a
# particular "path". Like `{} | setpath(["a","b"], …)`, but instead of making
# objects like `{"a":{"b":…}}`, this makes objects like `{"name":"a",
# "contents":[{"name":"b",…}]}`.
def tree($path):
    if ($path | length) <= 1
    then .name = $path[0]
    else { "name": $path[0], "contents": [ tree($path[1:]) ] }
    end
;

# Merge an array of page objects into a single page object.
def merge:
    map(to_entries) | add | group_by(.key) | map(
        { "key": (.[0].key)
        , "value": (
            if .[0].key == "contents"
            then [ .[].value ] | add | group_by(.name) | map(merge)
            elif [ .[].value == .[0].value ] | all
            then .[0].value
            else error("can't merge incompatible values")
            end
        ) }
    ) | from_entries
;

# Add paths to each object, that is, the names of the ancestors.
def directory:
    def f($d): .directory = $d | .name as $n | .contents[]? |= f($d+[$n]);
    f([])
;

# Every leaf node gets a basename, eg name without extension.
def basename:
    (all_children | select(has("contents") | not)) |= (
        .basename = (.name | sub(".([A-z]*)$";""))
    )
;

# Any Markdown page gets a link to its HTML page.
def link:
    (all_children | select(has("directory") and has("basename") and (.name | test(".(md|markdown)$";"i")))) |= (
        .link = ((.directory + [.basename + ".html"]) | join("/") | ltrimstr("./"))
    )
;

# Front matter is the page to be associated with the enclosing directory rather
# than itself.
def frontmatter:
    (all_children | select(has("contents"))) |= (
        (.frontmatter = [.contents[] | select(.meta.frontmatter | bool)][0]) |
        (.contents = .contents - [.frontmatter])
    )
;

# Drafts can be excluded from being uploaded and included in the table of
# contents. To not count as a draft, a document should be explicitly marked as
# "publish" in the metadata.
def explicit_publish:
    def publish: has("contents") or .external or .meta.publish | bool;
    (( all_children | select(publish | not)) |= mark) | remove_marked
;

# Sort content first according to sort order in metadata.
def sort_content:
    (all_children | select(has("contents")) | .contents) |= (
        sort_by(.meta.sort // .meta.title // .name)
    )
;

# Add a note that tells us whether this has only children who have no more
# subchildren.
def annotate_leaves:
    (all_children | select(has("contents"))) |= (
        .only_leaves = (.contents | all(has("contents") | not))
    )
;

# Combines the given stream of JSON objects by merging them, and performs the
# given operations to turn it into a proper index.
def index:
    merge
    | directory
    | basename
    | link
    | explicit_publish
    | frontmatter
    | sort_content
    | annotate_leaves
;

# Get publishable targets from an index, as an object containing the names of
# the relevant Makefile recipes.
def targets($dest):
    [ all_children
        | ., (.frontmatter // empty)
        | select(has("directory") and has("basename") and (has("external") | not))
        | .directory as $dir
        | {"target": "pdf-targets", "name": (.basename + ".pdf")}
        , {"target": "html-targets", "name": (.basename + ".html")}
        , {"target": "external-targets", "name": .targets?[]}
        | .name |= ($dir + [.] | join("/") | ltrimstr("./") | ($dest + "/" + .) )
    ]
    | group_by(.target)
    | map({(.[0].target): map(.name)})
    | add
;

# Turn a target object into makefile recipes.
def as_makefile:
    . + {".PHONY": keys} | to_entries[] | (.key + ": " + (.value | join(" ")))
;


:pencil: Implement 301 for HTML spreadsheets.

import module namespace hypercubes = "http://28.io/modules/xbrl/hypercubes";
import module namespace reports = "http://28.io/modules/xbrl/reports";
import module namespace components = "http://28.io/modules/xbrl/components";

import module namespace multiplexer = "http://28.io/modules/xbrl/profiles/multiplexer";
import module namespace fiscal-core = "http://28.io/modules/xbrl/profiles/sec/fiscal/core";

import module namespace config = "http://apps.28.io/config";
import module namespace session = "http://apps.28.io/session";
import module namespace api = "http://apps.28.io/api";
import module namespace request = "http://www.28msec.com/modules/http-request";

declare option rest:response "first-item";

(: Query parameters :)
declare  %rest:case-insensitive                 variable $token         as string? external;
declare  %rest:env                              variable $request-uri   as string  external;
declare  %rest:case-insensitive                 variable $format        as string? external;
declare  %rest:case-insensitive %rest:distinct  variable $cik           as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $edinetcode    as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $tag           as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $ticker        as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $sic           as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $fiscalYear    as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $fiscalPeriod  as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $fiscalPeriodType  as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $eid           as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $aid           as string* external;
declare  %rest:case-insensitive                 variable $validate      as boolean external := false;
declare  %rest:case-insensitive                 variable $eliminate     as boolean external := false;
declare  %rest:case-insensitive                 variable $elimination-threshold as integer external := 0;
declare  %rest:case-insensitive                 variable $report        as string? external;
declare  %rest:case-insensitive                 variable $profile-name  as string  external := $config:profile-name;
declare  %rest:case-insensitive                 variable $language      as string  external := "en-US";
declare  %rest:case-insensitive                 variable $debug         as boolean external := false;

(: Post-processing :)
let $format as string? := api:preprocess-format($format, $request-uri)
let $fiscalYear as integer* := api:preprocess-fiscal-years($fiscalYear)
let $fiscalPeriod as string* := api:preprocess-fiscal-periods($fiscalPeriod)
let $fiscalPeriodType as string* := api:preprocess-fiscal-period-types($fiscalPeriodType)
let $tag as string* := api:preprocess-tags($tag)

let $cik as string* :=
    switch($profile-name)
    case "sec" return $cik
    case "japan" return $edinetcode
    default return ()

(: Entity resolution :)
let $entities := multiplexer:entities(
  $profile-name,
  $eid,
  $cik,
  $tag,
  $ticker,
  $sic,
  (),
  (),
  (),
  ())

let $entities-not-found as boolean :=
  exists(($eid, $cik, $tag, $ticker, $sic)) and empty($entities)

let $report-id as string? := $report
let $report as object? := reports:reports($report)

return
if(empty($report))
then
{
      { status: 404 },
      session:error("report with id '" || $report-id || "' does not exist.", $format)
} else

    (: Fact resolution :)
    let $filter-override as object? :=
        if($profile-name eq "sec")
        then fiscal-core:filter-override(
            $entities,
            $fiscalYear,
            $fiscalPeriod,
            $fiscalPeriodType,
            $aid)
        else components:filter-override($entities, $aid)

    (: Fact resolution :)
    let $hypercube := hypercubes:hypercubes-for-components($report)[1]
    let $filtered-aspects := values($hypercube.Aspects)[exists(($$.Members, $$.DomainRestriction))]
    let $spreadsheet as object? :=
        if(count($filtered-aspects) lt $config:filtered-aspects and not exists(($filter-override)))
        then {
              { status: 403 },
              session:error("The report filters are too weak, which leads to too big an output.", $format)
        } else
            components:spreadsheet(
                $report,
                {|
                    { FilterOverride: $filter-override}[exists($filter-override)],
                    {
                        FlattenRows: true,
                        Eliminate: $eliminate,
                        EliminationThreshold: double($elimination-threshold) div 100,
                        Validate: $validate,
                        Language: $language,
                        Debug: $debug
                    }
                |}
            )
    let $results :=
        if($format eq "html")
        then {
          {
            status: 301,
            content-type: "text/html",
            serialization: { "method" : "html" },
            headers: { "Location" : "http://rendering.secxbrl.info/#?url=" || encode-for-uri("http://" || request:server-name() || ":" || request:server-port() || replace(request:uri(), "format=html", "format=json")) }
          },
          <html/>
        }
        else
        {
            { serialization: { method: "json", indent : true } },
            $spreadsheet
        }
    return if($entities-not-found)
           then api:not-found("entity")
           else api:check-and-return-results($token, $results, $format)

import module namespace hypercubes = "http://28.io/modules/xbrl/hypercubes";
import module namespace reports = "http://28.io/modules/xbrl/reports";
import module namespace components = "http://28.io/modules/xbrl/components";

import module namespace multiplexer = "http://28.io/modules/xbrl/profiles/multiplexer";
import module namespace fiscal-core = "http://28.io/modules/xbrl/profiles/sec/fiscal/core";

import module namespace config = "http://apps.28.io/config";
import module namespace session = "http://apps.28.io/session";
import module namespace api = "http://apps.28.io/api";

declare option rest:response "first-item";

(: Query parameters :)
declare  %rest:case-insensitive                 variable $token         as string? external;
declare  %rest:env                              variable $request-uri   as string  external;
declare  %rest:case-insensitive                 variable $format        as string? external;
declare  %rest:case-insensitive %rest:distinct  variable $cik           as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $edinetcode    as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $tag           as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $ticker        as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $sic           as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $fiscalYear    as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $fiscalPeriod  as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $fiscalPeriodType  as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $eid           as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $aid           as string* external;
declare  %rest:case-insensitive                 variable $validate      as boolean external := false;
declare  %rest:case-insensitive                 variable $eliminate     as boolean external := false;
declare  %rest:case-insensitive                 variable $elimination-threshold as integer external := 0;
declare  %rest:case-insensitive                 variable $report        as string? external;
declare  %rest:case-insensitive                 variable $profile-name  as string  external := $config:profile-name;
declare  %rest:case-insensitive                 variable $language      as string  external := "en-US";
declare  %rest:case-insensitive                 variable $debug         as boolean external := false;

(: Post-processing :)
let $format as string? := api:preprocess-format($format, $request-uri)
let $fiscalYear as integer* := api:preprocess-fiscal-years($fiscalYear)
let $fiscalPeriod as string* := api:preprocess-fiscal-periods($fiscalPeriod)
let $fiscalPeriodType as string* := api:preprocess-fiscal-period-types($fiscalPeriodType)
let $tag as string* := api:preprocess-tags($tag)

let $cik as string* :=
    switch($profile-name)
    case "sec" return $cik
    case "japan" return $edinetcode
    default return ()

(: Entity resolution :)
let $entities := multiplexer:entities(
  $profile-name,
  $eid,
  $cik,
  $tag,
  $ticker,
  $sic,
  (),
  (),
  (),
  ())

let $entities-not-found as boolean :=
  exists(($eid, $cik, $tag, $ticker, $sic)) and empty($entities)

let $report-id as string? := $report
let $report as object? := reports:reports($report)

return
if(empty($report))
then
{
      { status: 404 },
      session:error("report with id '" || $report-id || "' does not exist.", $format)
} else

    (: Fact resolution :)
    let $filter-override as object? :=
        if($profile-name eq "sec")
        then fiscal-core:filter-override(
            $entities,
            $fiscalYear,
            $fiscalPeriod,
            $fiscalPeriodType,
            $aid)
        else components:filter-override($entities, $aid)

    (: Fact resolution :)
    let $hypercube := hypercubes:hypercubes-for-components($report)[1]
    let $filtered-aspects := values($hypercube.Aspects)[exists(($$.Members, $$.DomainRestriction))]
    let $spreadsheet as object? :=
        if(count($filtered-aspects) lt $config:filtered-aspects and not exists(($filter-override)))
        then {
              { status: 403 },
              session:error("The report filters are too weak, which leads to too big an output.", $format)
        } else
            components:spreadsheet(
                $report,
                {|
                    { FilterOverride: $filter-override}[exists($filter-override)],
                    {
                        FlattenRows: true,
                        Eliminate: $eliminate,
                        EliminationThreshold: double($elimination-threshold) div 100,
                        Validate: $validate,
                        Language: $language,
                        Debug: $debug
                    }
                |}
            )
    let $results :=
        {
            { serialization: { method: "json", indent : true } },
            $spreadsheet
        }
    return if($entities-not-found)
           then api:not-found("entity")
           else api:check-and-return-results($token, $results, $format)


added future year to parameters if month > 4

jsoniq version "1.0";

import module namespace request = "http://www.28msec.com/modules/http-request";
import module namespace response = "http://www.28msec.com/modules/http-response";
import module namespace entities ="http://xbrl.io/modules/bizql/entities";
import module namespace mongo = "http://www.28msec.com/modules/mongodb";

let $param := lower-case(request:param-values("parameter"))

let $years :=
    (
        if(month-from-date(current-date()) gt 4)
        then year-from-date(current-date()) + 1
        else (),
        for $year in 2009 to fn:year-from-date(current-date())
        order by $year descending
        return $year
    )

let $periods := ("FY", "Q3", "Q2", "Q1")

let $sics :=
    let $c := mongo:connect("xbrl", {})
    return
        for $s in mongo:find($c, "sics")
        group by $s.ID
        return {
            ID: $s[1].ID,
            Description: $s[1].Description,
            Sector: $s[1].Sector
        }

let $tags := ("DOW30", "SP500", "FORTUNE100", "PJI")

let $entities :=
    for $entity in entities:entities()
    return {
        name: $entity.Profiles.SEC.CompanyName,
        tickers: $entity.Profiles.SEC.Tickers,
        cik: $entity.Profiles.SEC.CIK,
        tags: $entity.Profiles.SEC.Tags,
        sic: $entity.Profiles.SEC.SIC
    }

return
    {
        response:content-type("application/json");
        response:serialization-parameters({"indent" : true});

        switch (true)
        case $param eq "years"
        return
            {
                years: [ $years ]
            }
        case $param eq "periods"
        return
            {
                periods: [ $periods ]
            }
        case $param eq "sics"
        return
            {
                sics: [ $sics ]
            }
        case $param eq "tags"
        return
            {
                tags: [ $tags ]
            }
        case $param eq "entities"
        return
            {
                entities: [ $entities ]
            }
        default
        return
            {
                years: [ $years ],
                periods: [ $periods ],
                sics: [ $sics ],
                tags: [ $tags ],
                entities: [ $entities ]
            }
    }

jsoniq version "1.0";

import module namespace request = "http://www.28msec.com/modules/http-request";
import module namespace response = "http://www.28msec.com/modules/http-response";
import module namespace entities ="http://xbrl.io/modules/bizql/entities";
import module namespace mongo = "http://www.28msec.com/modules/mongodb";

let $param := lower-case(request:param-values("parameter"))

let $years :=
    for $year in 2009 to fn:year-from-date(current-date())
    order by $year descending
    return $year

let $periods := ("FY", "Q3", "Q2", "Q1")

let $sics :=
    let $c := mongo:connect("xbrl", {})
    return
        for $s in mongo:find($c, "sics")
        group by $s.ID
        return {
            ID: $s[1].ID,
            Description: $s[1].Description,
            Sector: $s[1].Sector
        }

let $tags := ("DOW30", "SP500", "FORTUNE100", "PJI")

let $entities :=
    for $entity in entities:entities()
    return {
        name: $entity.Profiles.SEC.CompanyName,
        tickers: $entity.Profiles.SEC.Tickers,
        cik: $entity.Profiles.SEC.CIK,
        tags: $entity.Profiles.SEC.Tags,
        sic: $entity.Profiles.SEC.SIC
    }

return
    {
        response:content-type("application/json");
        response:serialization-parameters({"indent" : true});

        switch (true)
        case $param eq "years"
        return
            {
                years: [ $years ]
            }
        case $param eq "periods"
        return
            {
                periods: [ $periods ]
            }
        case $param eq "sics"
        return
            {
                sics: [ $sics ]
            }
        case $param eq "tags"
        return
            {
                tags: [ $tags ]
            }
        case $param eq "entities"
        return
            {
                entities: [ $entities ]
            }
        default
        return
            {
                years: [ $years ],
                periods: [ $periods ],
                sics: [ $sics ],
                tags: [ $tags ],
                entities: [ $entities ]
            }
    }


allowing LATEST filter for fiscal year

allowing LATEST filter for fiscal year

jsoniq version "1.0";

import module namespace request = "http://www.28msec.com/modules/http-request";
import module namespace response = "http://www.28msec.com/modules/http-response";
import module namespace entities ="http://xbrl.io/modules/bizql/entities";
import module namespace mongo = "http://www.28msec.com/modules/mongodb";

let $param := lower-case(request:param-values("parameter"))

let $years :=
    (
        "LATEST",
        for $year in 2009 to fn:year-from-date(current-date())
        order by $year descending
        return $year
    )

let $periods := ("FY", "Q3", "Q2", "Q1")

let $sics :=
    let $c := mongo:connect("xbrl", {})
    return
        for $s in mongo:find($c, "sics")
        return {
            ID: $s.ID,
            Description: $s.Description,
            Sector: $s.Sector
        }

let $tags := ("DOW30", "SP500", "FORTUNE100", "PJI")

let $entities :=
    for $entity in entities:entities()
    return {
        name: $entity.Profiles.SEC.CompanyName,
        tickers: $entity.Profiles.SEC.Tickers,
        cik: $entity.Profiles.SEC.CIK,
        tags: $entity.Profiles.SEC.Tags,
        sic: $entity.Profiles.SEC.SIC
    }

return
    {
        response:content-type("application/json");
        response:serialization-parameters({"indent" : true});

        switch (true)
        case $param eq "years"
        return
            {
                years: [ $years ]
            }
        case $param eq "periods"
        return
            {
                periods: [ $periods ]
            }
        case $param eq "sics"
        return
            {
                sics: [ $sics ]
            }
        case $param eq "tags"
        return
            {
                tags: [ $tags ]
            }
        case $param eq "entities"
        return
            {
                entities: [ $entities ]
            }
        default
        return
            {
                years: [ $years ],
                periods: [ $periods ],
                sics: [ $sics ],
                tags: [ $tags ],
                entities: [ $entities ]
            }
    }

jsoniq version "1.0";

import module namespace request = "http://www.28msec.com/modules/http-request";
import module namespace response = "http://www.28msec.com/modules/http-response";
import module namespace entities ="http://xbrl.io/modules/bizql/entities";
import module namespace mongo = "http://www.28msec.com/modules/mongodb";

let $param := lower-case(request:param-values("parameter"))

let $years :=
    for $year in 2009 to fn:year-from-date(current-date())
    order by $year descending
    return $year

let $periods := ("FY", "Q3", "Q2", "Q1")

let $sics :=
    let $c := mongo:connect("xbrl", {})
    return
        for $s in mongo:find($c, "sics")
        return {
            ID: $s.ID,
            Description: $s.Description,
            Sector: $s.Sector
        }

let $tags := ("DOW30", "SP500", "FORTUNE100", "PJI")

let $entities :=
    for $entity in entities:entities()
    return {
        name: $entity.Profiles.SEC.CompanyName,
        tickers: $entity.Profiles.SEC.Tickers,
        cik: $entity.Profiles.SEC.CIK,
        tags: $entity.Profiles.SEC.Tags,
        sic: $entity.Profiles.SEC.SIC
    }

return
    {
        response:content-type("application/json");
        response:serialization-parameters({"indent" : true});

        switch (true)
        case $param eq "years"
        return
            {
                years: [ $years ]
            }
        case $param eq "periods"
        return
            {
                periods: [ $periods ]
            }
        case $param eq "sics"
        return
            {
                sics: [ $sics ]
            }
        case $param eq "tags"
        return
            {
                tags: [ $tags ]
            }
        case $param eq "entities"
        return
            {
                entities: [ $entities ]
            }
        default
        return
            {
                years: [ $years ],
                periods: [ $periods ],
                sics: [ $sics ],
                tags: [ $tags ],
                entities: [ $entities ]
            }
    }


Add more debugging

Add more debugging

import module namespace response = "http://www.28msec.com/modules/http-response";
import module namespace request = "http://www.28msec.com/modules/http-request";
import module namespace test = "http://apps.28.io/test";
import module namespace http-client = "http://zorba.io/modules/http-client";

declare %an:nondeterministic function local:test-values($params as object, $expected-file as string) as item*
{
    let $endpoint := "spreadsheet-for-component"
    let $request := test:invoke($endpoint, $params)
    let $actual as object := $request[2]
    let $expected := parse-json(
        http-client:get("http://" || request:server-name() || ":" || request:server-port() ||
                        "/test/edinet/" || $expected-file).body.content)
    return if (deep-equal($actual, $expected))
           then true
           else {
                url: test:url($endpoint, $params),
                actual: $actual,
                expected: $expected
           }
};

declare %an:sequential function local:check($o as object) as object
{
    if (not(every $k in (keys($o) ! $o.$$) satisfies ($k instance of boolean and $k)))
    then {
            response:status-code(500);
            $o
    } else
            $o
};

local:check({
    bs-one: local:test-values(
      {
        eid: "http://info.edinet-fsa.go.jp E01225-000",
        fiscalYear: "2014",
        fiscalPeriod: "Q1",
        role: "http://disclosure.edinet-fsa.go.jp/role/jppfs/rol_QuarterlyConsolidatedBalanceSheet",
        merge: "true"
      },
      "spreadsheet-for-component-expected-bs-one.jq"),
    pl-one: local:test-values(
      {
        eid: "http://info.edinet-fsa.go.jp E01225-000",
        fiscalYear: "2014",
        fiscalPeriod: "Q1",
        role: "http://disclosure.edinet-fsa.go.jp/role/jppfs/rol_YearToQuarterEndConsolidatedStatementOfIncome",
        merge: "true"
      },
      "spreadsheet-for-component-expected-pl-one.jq"),
    cf-one: local:test-values(
      {
        eid: "http://info.edinet-fsa.go.jp E01225-000",
        fiscalYear: "2014",
        fiscalPeriod: "Q1",
        role: "http://disclosure.edinet-fsa.go.jp/role/jpcrp/rol_NotesQuarterlyConsolidatedStatementOfCashFlows",
        merge: "true"
      },
      "spreadsheet-for-component-expected-cf-one.jq"),
    bs-companies: local:test-values(
      {
        tag: "ALL",
        fiscalYear: "2014",
        fiscalPeriod: "Q1",
        role: "http://disclosure.edinet-fsa.go.jp/role/jppfs/rol_QuarterlyConsolidatedBalanceSheet",
        merge: "true"
      },
      "spreadsheet-for-component-expected-bs-companies.jq"),
    pl-companies: local:test-values(
      {
        tag: "ALL",
        fiscalYear: "2014",
        fiscalPeriod: "Q1",
        role: "http://disclosure.edinet-fsa.go.jp/role/jppfs/rol_YearToQuarterEndConsolidatedStatementOfIncome",
        merge: "true"
      },
      "spreadsheet-for-component-expected-pl-companies.jq"),
    cf-companies: local:test-values(
      {
        tag: "ALL",
        fiscalYear: "2014",
        fiscalPeriod: "Q1",
        role: "http://disclosure.edinet-fsa.go.jp/role/jpcrp/rol_NotesQuarterlyConsolidatedStatementOfCashFlows",
        merge: "true"
      },
      "spreadsheet-for-component-expected-cf-companies.jq"),
    bs-periods: local:test-values(
      {
        eid: "http://info.edinet-fsa.go.jp E01225-000",
        fiscalYear: "ALL",
        fiscalPeriod: "FY",
        role: "http://info.edinet-fsa.go.jp/jp/fr/gaap/role/ConsolidatedBalanceSheets",
        merge: "true"
      },
      "spreadsheet-for-component-expected-bs-periods.jq"),
    pl-periods: local:test-values(
      {
        eid: "http://info.edinet-fsa.go.jp E01225-000",
        fiscalYear: "ALL",
        fiscalPeriod: "FY",
        role: "http://info.edinet-fsa.go.jp/jp/fr/gaap/role/ConsolidatedStatementsOfIncome",
        merge: "true"
      },
      "spreadsheet-for-component-expected-pl-periods.jq"),
    cf-periods: local:test-values(
      {
        eid: "http://info.edinet-fsa.go.jp E01225-000",
        fiscalYear: "ALL",
        fiscalPeriod: "FY",
        role: "http://info.edinet-fsa.go.jp/jp/fr/gaap/role/ConsolidatedStatementsOfCashFlowsIndirect",
        merge: "true"
      },
      "spreadsheet-for-component-expected-cf-periods.jq")
})

import module namespace response = "http://www.28msec.com/modules/http-response";
import module namespace request = "http://www.28msec.com/modules/http-request";
import module namespace test = "http://apps.28.io/test";
import module namespace http-client = "http://zorba.io/modules/http-client";

declare %an:nondeterministic function local:test-values($params as object, $expected-file as string) as item*
{
    let $endpoint := "spreadsheet-for-component"
    let $request := test:invoke($endpoint, $params)
    let $actual as object := $request[2]
    let $expected := parse-json(
        http-client:get("http://" || request:server-name() || ":" || request:server-port() ||
                        "/test/edinet/" || $expected-file).body.content)
    return if (deep-equal($actual, $expected))
           then true
           else { url: test:url($endpoint, $params) }
};

declare %an:sequential function local:check($o as object) as object
{
    if (not(every $k in (keys($o) ! $o.$$) satisfies ($k instance of boolean and $k)))
    then {
            response:status-code(500);
            $o
    } else
            $o
};

local:check({
    bs-one: local:test-values(
      {
        eid: "http://info.edinet-fsa.go.jp E01225-000",
        fiscalYear: "2014",
        fiscalPeriod: "Q1",
        role: "http://disclosure.edinet-fsa.go.jp/role/jppfs/rol_QuarterlyConsolidatedBalanceSheet",
        merge: "true"
      },
      "spreadsheet-for-component-expected-bs-one.jq"),
    pl-one: local:test-values(
      {
        eid: "http://info.edinet-fsa.go.jp E01225-000",
        fiscalYear: "2014",
        fiscalPeriod: "Q1",
        role: "http://disclosure.edinet-fsa.go.jp/role/jppfs/rol_YearToQuarterEndConsolidatedStatementOfIncome",
        merge: "true"
      },
      "spreadsheet-for-component-expected-pl-one.jq"),
    cf-one: local:test-values(
      {
        eid: "http://info.edinet-fsa.go.jp E01225-000",
        fiscalYear: "2014",
        fiscalPeriod: "Q1",
        role: "http://disclosure.edinet-fsa.go.jp/role/jpcrp/rol_NotesQuarterlyConsolidatedStatementOfCashFlows",
        merge: "true"
      },
      "spreadsheet-for-component-expected-cf-one.jq"),
    bs-companies: local:test-values(
      {
        tag: "ALL",
        fiscalYear: "2014",
        fiscalPeriod: "Q1",
        role: "http://disclosure.edinet-fsa.go.jp/role/jppfs/rol_QuarterlyConsolidatedBalanceSheet",
        merge: "true"
      },
      "spreadsheet-for-component-expected-bs-companies.jq"),
    pl-companies: local:test-values(
      {
        tag: "ALL",
        fiscalYear: "2014",
        fiscalPeriod: "Q1",
        role: "http://disclosure.edinet-fsa.go.jp/role/jppfs/rol_YearToQuarterEndConsolidatedStatementOfIncome",
        merge: "true"
      },
      "spreadsheet-for-component-expected-pl-companies.jq"),
    cf-companies: local:test-values(
      {
        tag: "ALL",
        fiscalYear: "2014",
        fiscalPeriod: "Q1",
        role: "http://disclosure.edinet-fsa.go.jp/role/jpcrp/rol_NotesQuarterlyConsolidatedStatementOfCashFlows",
        merge: "true"
      },
      "spreadsheet-for-component-expected-cf-companies.jq"),
    bs-periods: local:test-values(
      {
        eid: "http://info.edinet-fsa.go.jp E01225-000",
        fiscalYear: "ALL",
        fiscalPeriod: "FY",
        role: "http://info.edinet-fsa.go.jp/jp/fr/gaap/role/ConsolidatedBalanceSheets",
        merge: "true"
      },
      "spreadsheet-for-component-expected-bs-periods.jq"),
    pl-periods: local:test-values(
      {
        eid: "http://info.edinet-fsa.go.jp E01225-000",
        fiscalYear: "ALL",
        fiscalPeriod: "FY",
        role: "http://info.edinet-fsa.go.jp/jp/fr/gaap/role/ConsolidatedStatementsOfIncome",
        merge: "true"
      },
      "spreadsheet-for-component-expected-pl-periods.jq"),
    cf-periods: local:test-values(
      {
        eid: "http://info.edinet-fsa.go.jp E01225-000",
        fiscalYear: "ALL",
        fiscalPeriod: "FY",
        role: "http://info.edinet-fsa.go.jp/jp/fr/gaap/role/ConsolidatedStatementsOfCashFlowsIndirect",
        merge: "true"
      },
      "spreadsheet-for-component-expected-cf-periods.jq")
})


fixed bug if dei:LegalEntityAxis is present as a custom dimension

import module namespace companies = "http://xbrl.io/modules/bizql/profiles/sec/companies";
import module namespace archives = "http://xbrl.io/modules/bizql/archives";
import module namespace sec-fiscal = "http://xbrl.io/modules/bizql/profiles/sec/fiscal/core";

import module namespace hypercubes = "http://xbrl.io/modules/bizql/hypercubes";
import module namespace response = "http://www.28msec.com/modules/http-response";
import module namespace request = "http://www.28msec.com/modules/http-request";
import module namespace session = "http://apps.28.io/session";
import module namespace csv = "http://zorba.io/modules/json-csv";

declare function local:to-csv($o as object*) as string?
{
    if (exists($o)) (: bug in csv:serialize :)
    then
    string-join(
        csv:serialize(
            for $o in $o
            let $a := $o.Aspects
            return {|
                for $k in keys($a)
                return { $k : $a.$k },
                { "Value" : $o.Value },
                if (exists($o."Unit"))
                then { "Unit" :  $o."Unit" }
                else (),
                if (exists($o.Decimals))
                then { "Decimals" : $o.Decimals }
                else(),
                { "EntityRegistrantName" : $o.EntityRegistrantName },
                if (exists($o.ReportedConcept))
                then { "ReportedConcept" : $o.ReportedConcept }
                else ()
            |},
            { serialize-null-as : "" }
        )
    )
    else ()
};

declare function local:to-xml($o as object*) as node()*
{
    (session:comment("xml", {
        NumFacts: count($o),
        TotalNumFacts: session:num-facts(),
        TotalNumArchives: session:num-archives(),
        TotalNumEntities: session:num-entities()
    }),
    <FactTable NetworkIdentifier="http://bizql.io/facts"
            TableName="xbrl:Facts">{
        for $o in $o
        let $a := $o.Aspects
        return
            <Fact>{
                <Aspects>{
                    for $k in keys($a)
                    return
                        <Aspect>
                            <Name>{$k}</Name>
                            <Value>{$a.$k}</Value>
                        </Aspect>
                }</Aspects>,
                <Value>{$o.Value}</Value>,
                <Type>{$o.Type}</Type>,
                if (exists($o.Unit))
                then <Unit>{$o.Unit}</Unit>
                else(),
                if (exists($o.Decimals))
                then <Decimals>{$o.Decimals}</Decimals>
                else (),
                <EntityRegistrantName>{$o.EntityRegistrantName}</EntityRegistrantName>,
                if (exists($o.ReportedConcept))
                then <ReportedConcept>{$o."ReportedConcept"}</ReportedConcept>
                else ()
            }</Fact>
    }</FactTable>)
};

declare function local:hypercube() as object
{
    hypercubes:user-defined-hypercube({|
        let $concepts := (request:param-values("concept"), request:param-values("xbrl:Concept"))
        return
            if (exists($concepts))
            then { "xbrl:Concept" : { Domain : [ $concepts ] } }
            else (),

        if (not(request:param-names() = "dei:LegalEntityAxis"))
        then {
                "dei:LegalEntityAxis" : {
                    "Domain" : [ "sec:DefaultLegalEntity" ],
                    "Default" : "sec:DefaultLegalEntity"
                }
        } else (),

        for $p in request:param-names()
        where contains($p, ":") and not(starts-with($p, "xbrl:Concept"))
        group by $dimension-name := if (ends-with(lower-case($p), "::default"))
                                    then substring-before($p, "::default")
                                    else if (ends-with(lower-case($p), ":default"))
                                    then substring-before($p, ":default")
                                    else $p
        let $all := (request:param-values($dimension-name) ! upper-case($$)) = "ALL"
        return
        {
            $dimension-name : {|
                let $v := request:param-values($dimension-name)
                return
                    if (exists($v) and not($all))
                    then { "Domain" : [ $v ] }
                    else (),

            let $predefined-default := collection("defaultaxis")[$$.axis eq $dimension-name]
            let $is-default := ($p = $dimension-name || "::default") or ($p = $dimension-name || ":default")
            return
                if (exists($predefined-default) and not($is-default))
                then { "Default" : $predefined-default.default }
                else if ($is-default)
                then {
                        "Default" : (
                                request:param-values($dimension-name || "::default"),
                                request:param-values($dimension-name || ":default")
                            )[1]
                    }
                else ()
            |}
        }
    |})
};

declare function local:facts(
    $archives as object*,
    $map as string?,
    $rules as string?) as object*
{
    for $fact in
        for $f in hypercubes:facts-for-hypercube(local:hypercube(), $archives,
            {|
                if (exists($map)) then { "concept-maps" : $map } else (),
                if (exists($rules)) then { "Rules" : $rules } else ()
            |}
        )
        where exists($f.Profiles.SEC.Fiscal.Year)
        group by $f.Aspects."xbrl:Entity",
                 $f.Profiles.SEC.Fiscal.Year,
                 $f.Profiles.SEC.Fiscal.Period,
                 $f.Aspects."xbrl:Concept"
        let $latest-accepted := max(distinct-values($f.Profiles.SEC.Accepted))
        return if (empty($latest-accepted))
               then $f
               else $f[$$.Profiles.SEC.Accepted eq $latest-accepted]
    return {|
        { Aspects : {|
            for $a in keys($fact.Aspects)
            where $a ne "xbrl:Unit"
            return { $a : $fact.Aspects.$a },
            { "bizql:FiscalPeriod" : $fact.Profiles.SEC.Fiscal.Period },
            { "bizql:FiscalYear" : $fact.Profiles.SEC.Fiscal.Year }
        |} },
        { Type: $fact.Type },
        if (exists($fact.Aspects."xbrl:Unit"))
        then { Unit: $fact.Aspects."xbrl:Unit" }
        else  (),
        if (exists($fact.Decimals))
        then { Decimals: $fact.Decimals }
        else (),
        { Value: $fact.Value },
        { "EntityRegistrantName" : companies:companies($fact.Aspects."xbrl:Entity").Profiles.SEC.CompanyName},
        if (exists($map) and ($fact."xbrl28:Type" eq "xbrl28:concept-maps"))
        then { "ReportedConcept" : $fact.AuditTrails[][$$.Type eq "xbrl28:concept-maps"].Data.OriginalConcept[1] }
        else ()
    |}
};

declare function local:filings(
    $ciks as string*,
    $tags as string*,
    $tickers as string*,
    $sics as string*,
    $fp as string*,
    $fy as string*) as object*
{
    let $entities := (
        companies:companies($ciks),
        companies:companies-for-tags($tags),
        companies:companies-for-tickers($tickers),
        companies:companies-for-SIC($sics)
    )
    for $entity in $entities
    for $fy in distinct-values(
                for $fy in $fy
                return
                    switch ($fy)
                    case "LATEST" return
                        for $p in $fp
                        return
                            if ($p eq "FY")
                            then sec-fiscal:latest-reported-fiscal-period($entity, "10-K").year
                            else sec-fiscal:latest-reported-fiscal-period($entity, "10-Q").year
                        case "ALL" return  $sec-fiscal:ALL_FISCAL_YEARS
                    default return $fy
                )
    for $fp in $fp
    return sec-fiscal:filings-for-entities-and-fiscal-periods-and-years($entity, $fp, $fy cast as integer)
};

let $format      := lower-case(request:param-values("format")[1])

(: choose
    1. entities (using ciks, tags, tickers, sics), FY, and FP ) or
    2. accession numbers
:)
let $ciks        := distinct-values(companies:eid(request:param-values("cik")))
let $tags        := distinct-values(request:param-values("tag") ! upper-case($$))
let $tickers     := distinct-values(request:param-values("ticker"))
let $sics        := distinct-values(request:param-values("sic"))
let $fiscalYears := distinct-values(
                        for $y in request:param-values("fiscalYear", "LATEST")
                        return
                            if ($y eq "LATEST" or $y eq "ALL")
                            then $y
                            else if ($y castable as integer)
                            then $y
                            else ()
                    )
let $fiscalPeriods := distinct-values(let $fp := request:param-values("fiscalPeriod", "FY")
                      return
                        if (($fp ! lower-case($$)) = "all")
                        then $sec-fiscal:ALL_FISCAL_PERIODS
                        else $fp)
let $aids     := request:param-values("aid")
let $map      := request:param-values("map")[1]
let $rules    := request:param-values("rules")[1]
let $archives := (
                    local:filings($ciks, $tags, $tickers, $sics, $fiscalPeriods, $fiscalYears),
                    archives:archives($aids)
                 )
let $entities := companies:companies($archives.Entity)
return
    switch(true)
    case empty($archives) return {
        response:status-code(400);
        session:error("entities or archives not found (valid parameters: cik, ticker, tag, sic, aid)", $format)
    }
    case not (session:only-dow30($entities) or session:valid()) return {
        response:status-code(401);
        session:error("accessing facts of an entity that is not in the DOW30", $format)
    }
    default return
        let $facts := local:facts($archives, $map, $rules)
        return
            switch ($format)
            case "xml" return {
                response:serialization-parameters({"omit-xml-declaration" : false, indent : true });
                local:to-xml($facts)
            }
            case "text" case "csv" return {
                response:content-type("text/csv");
                response:header("Content-Disposition", "attachment; filename=facts.csv");
                local:to-csv($facts)
            }
            case "excel" return {
                response:content-type("application/vnd.ms-excel");
                response:header("Content-Disposition", "attachment; filename=fact.csv");
                local:to-csv($facts)
            }
            default return {
                response:content-type("application/json");
                response:serialization-parameters({"indent" : true});
                {|
                    { NetworkIdentifier : "http://bizql.io/facts" },
                    { TableName : "xbrl:Facts" },
                    { FactTable : [ $facts ] },
                    session:comment("json", {
                            NumFacts: count($facts),
                            TotalNumFacts: session:num-facts(),
                            TotalNumArchives: session:num-archives(),
                            TotalNumEntities: session:num-entities()
                        })
                |}
            }

import module namespace companies = "http://xbrl.io/modules/bizql/profiles/sec/companies";
import module namespace archives = "http://xbrl.io/modules/bizql/archives";
import module namespace sec-fiscal = "http://xbrl.io/modules/bizql/profiles/sec/fiscal/core";

import module namespace hypercubes = "http://xbrl.io/modules/bizql/hypercubes";
import module namespace response = "http://www.28msec.com/modules/http-response";
import module namespace request = "http://www.28msec.com/modules/http-request";
import module namespace session = "http://apps.28.io/session";
import module namespace csv = "http://zorba.io/modules/json-csv";

declare function local:to-csv($o as object*) as string?
{
    if (exists($o)) (: bug in csv:serialize :)
    then
    string-join(
        csv:serialize(
            for $o in $o
            let $a := $o.Aspects
            return {|
                for $k in keys($a)
                return { $k : $a.$k },
                { "Value" : $o.Value },
                if (exists($o."Unit"))
                then { "Unit" :  $o."Unit" }
                else (),
                if (exists($o.Decimals))
                then { "Decimals" : $o.Decimals }
                else(),
                { "EntityRegistrantName" : $o.EntityRegistrantName },
                if (exists($o.ReportedConcept))
                then { "ReportedConcept" : $o.ReportedConcept }
                else ()
            |},
            { serialize-null-as : "" }
        )
    )
    else ()
};

declare function local:to-xml($o as object*) as node()*
{
    (session:comment("xml", {
        NumFacts: count($o),
        TotalNumFacts: session:num-facts(),
        TotalNumArchives: session:num-archives(),
        TotalNumEntities: session:num-entities()
    }),
    <FactTable NetworkIdentifier="http://bizql.io/facts"
            TableName="xbrl:Facts">{
        for $o in $o
        let $a := $o.Aspects
        return
            <Fact>{
                <Aspects>{
                    for $k in keys($a)
                    return
                        <Aspect>
                            <Name>{$k}</Name>
                            <Value>{$a.$k}</Value>
                        </Aspect>
                }</Aspects>,
                <Value>{$o.Value}</Value>,
                <Type>{$o.Type}</Type>,
                if (exists($o.Unit))
                then <Unit>{$o.Unit}</Unit>
                else(),
                if (exists($o.Decimals))
                then <Decimals>{$o.Decimals}</Decimals>
                else (),
                <EntityRegistrantName>{$o.EntityRegistrantName}</EntityRegistrantName>,
                if (exists($o.ReportedConcept))
                then <ReportedConcept>{$o."ReportedConcept"}</ReportedConcept>
                else ()
            }</Fact>
    }</FactTable>)
};

declare function local:hypercube() as object
{
    hypercubes:user-defined-hypercube({|
        let $concepts := (request:param-values("concept"), request:param-values("xbrl:Concept"))
        return
            if (exists($concepts))
            then { "xbrl:Concept" : { Domain : [ $concepts ] } }
            else (),

        if (not(keys(request:param-names()) = "dei:LegalEntityAxis"))
        then {
                "dei:LegalEntityAxis" : {
                    "Domain" : [ "sec:DefaultLegalEntity" ],
                    "Default" : "sec:DefaultLegalEntity"
                }
        } else (),

        for $p in request:param-names()
        where contains($p, ":") and not(starts-with($p, "xbrl:Concept"))
        group by $dimension-name := if (ends-with(lower-case($p), "::default"))
                                    then substring-before($p, "::default")
                                    else if (ends-with(lower-case($p), ":default"))
                                    then substring-before($p, ":default")
                                    else $p
        let $all := (request:param-values($dimension-name) ! upper-case($$)) = "ALL"
        return
        {
            $dimension-name : {|
                let $v := request:param-values($dimension-name)
                return
                    if (exists($v) and not($all))
                    then { "Domain" : [ $v ] }
                    else (),

            let $predefined-default := collection("defaultaxis")[$$.axis eq $dimension-name]
            let $is-default := ($p = $dimension-name || "::default") or ($p = $dimension-name || ":default")
            return
                if (exists($predefined-default) and not($is-default))
                then { "Default" : $predefined-default.default }
                else if ($is-default)
                then {
                        "Default" : (
                                request:param-values($dimension-name || "::default"),
                                request:param-values($dimension-name || ":default")
                            )[1]
                    }
                else ()
            |}
        }
    |})
};

declare function local:facts(
    $archives as object*,
    $map as string?,
    $rules as string?) as object*
{
    for $fact in
        for $f in hypercubes:facts-for-hypercube(local:hypercube(), $archives,
            {|
                if (exists($map)) then { "concept-maps" : $map } else (),
                if (exists($rules)) then { "Rules" : $rules } else ()
            |}
        )
        where exists($f.Profiles.SEC.Fiscal.Year)
        group by $f.Aspects."xbrl:Entity",
                 $f.Profiles.SEC.Fiscal.Year,
                 $f.Profiles.SEC.Fiscal.Period,
                 $f.Aspects."xbrl:Concept"
        let $latest-accepted := max(distinct-values($f.Profiles.SEC.Accepted))
        return if (empty($latest-accepted))
               then $f
               else $f[$$.Profiles.SEC.Accepted eq $latest-accepted]
    return {|
        { Aspects : {|
            for $a in keys($fact.Aspects)
            where $a ne "xbrl:Unit"
            return { $a : $fact.Aspects.$a },
            { "bizql:FiscalPeriod" : $fact.Profiles.SEC.Fiscal.Period },
            { "bizql:FiscalYear" : $fact.Profiles.SEC.Fiscal.Year }
        |} },
        { Type: $fact.Type },
        if (exists($fact.Aspects."xbrl:Unit"))
        then { Unit: $fact.Aspects."xbrl:Unit" }
        else  (),
        if (exists($fact.Decimals))
        then { Decimals: $fact.Decimals }
        else (),
        { Value: $fact.Value },
        { "EntityRegistrantName" : companies:companies($fact.Aspects."xbrl:Entity").Profiles.SEC.CompanyName},
        if (exists($map) and ($fact."xbrl28:Type" eq "xbrl28:concept-maps"))
        then { "ReportedConcept" : $fact.AuditTrails[][$$.Type eq "xbrl28:concept-maps"].Data.OriginalConcept[1] }
        else ()
    |}
};

declare function local:filings(
    $ciks as string*,
    $tags as string*,
    $tickers as string*,
    $sics as string*,
    $fp as string*,
    $fy as string*) as object*
{
    let $entities := (
        companies:companies($ciks),
        companies:companies-for-tags($tags),
        companies:companies-for-tickers($tickers),
        companies:companies-for-SIC($sics)
    )
    for $entity in $entities
    for $fy in distinct-values(
                for $fy in $fy
                return
                    switch ($fy)
                    case "LATEST" return
                        for $p in $fp
                        return
                            if ($p eq "FY")
                            then sec-fiscal:latest-reported-fiscal-period($entity, "10-K").year
                            else sec-fiscal:latest-reported-fiscal-period($entity, "10-Q").year
                        case "ALL" return  $sec-fiscal:ALL_FISCAL_YEARS
                    default return $fy
                )
    for $fp in $fp
    return sec-fiscal:filings-for-entities-and-fiscal-periods-and-years($entity, $fp, $fy cast as integer)
};

let $format      := lower-case(request:param-values("format")[1])

(: choose
    1. entities (using ciks, tags, tickers, sics), FY, and FP ) or
    2. accession numbers
:)
let $ciks        := distinct-values(companies:eid(request:param-values("cik")))
let $tags        := distinct-values(request:param-values("tag") ! upper-case($$))
let $tickers     := distinct-values(request:param-values("ticker"))
let $sics        := distinct-values(request:param-values("sic"))
let $fiscalYears := distinct-values(
                        for $y in request:param-values("fiscalYear", "LATEST")
                        return
                            if ($y eq "LATEST" or $y eq "ALL")
                            then $y
                            else if ($y castable as integer)
                            then $y
                            else ()
                    )
let $fiscalPeriods := distinct-values(let $fp := request:param-values("fiscalPeriod", "FY")
                      return
                        if (($fp ! lower-case($$)) = "all")
                        then $sec-fiscal:ALL_FISCAL_PERIODS
                        else $fp)
let $aids     := request:param-values("aid")
let $map      := request:param-values("map")[1]
let $rules    := request:param-values("rules")[1]
let $archives := (
                    local:filings($ciks, $tags, $tickers, $sics, $fiscalPeriods, $fiscalYears),
                    archives:archives($aids)
                 )
let $entities := companies:companies($archives.Entity)
return
    switch(true)
    case empty($archives) return {
        response:status-code(400);
        session:error("entities or archives not found (valid parameters: cik, ticker, tag, sic, aid)", $format)
    }
    case not (session:only-dow30($entities) or session:valid()) return {
        response:status-code(401);
        session:error("accessing facts of an entity that is not in the DOW30", $format)
    }
    default return
        let $facts := local:facts($archives, $map, $rules)
        return
            switch ($format)
            case "xml" return {
                response:serialization-parameters({"omit-xml-declaration" : false, indent : true });
                local:to-xml($facts)
            }
            case "text" case "csv" return {
                response:content-type("text/csv");
                response:header("Content-Disposition", "attachment; filename=facts.csv");
                local:to-csv($facts)
            }
            case "excel" return {
                response:content-type("application/vnd.ms-excel");
                response:header("Content-Disposition", "attachment; filename=fact.csv");
                local:to-csv($facts)
            }
            default return {
                response:content-type("application/json");
                response:serialization-parameters({"indent" : true});
                {|
                    { NetworkIdentifier : "http://bizql.io/facts" },
                    { TableName : "xbrl:Facts" },
                    { FactTable : [ $facts ] },
                    session:comment("json", {
                            NumFacts: count($facts),
                            TotalNumFacts: session:num-facts(),
                            TotalNumArchives: session:num-archives(),
                            TotalNumEntities: session:num-entities()
                        })
                |}
            }


Add "sortby" key to sort articles.

Add "sortby" key to sort articles.

#!/usr/bin/env jq
# This is a collection of filters for `jq`, intended to manipulate JSON objects
# into JSON representing a website index, for further processing in a template.

# Convert "truthy" value to actual boolean.
def bool:
    [. == (null,false,0,{},[])] | any | not
;

# Is a given array at least length $n?
def at_least($n):
    (. | length) >= $n
;

# Generate this object and all its descendants.
def entries:
    ., recurse(.contents?[]?)
;

# Wrap an object in other objects so that the original object exists at a
# particular "path". Like `{} | setpath(["a","b"], …)`, but instead of making
# objects like `{"a":{"b":…}}`, this makes objects like `{"name":"a",
# "contents":[{"name":"b",…}]}`. We use `name` and `contents` to be compatible
# with the output of the `tree` program on the shell.
def tree($path):
    if $path | at_least(2)
    then { "contents": [ tree($path[1:]) ] }
    else .
    end | .name = $path[0]
;

# Merge an array of page objects into a single page object.
def merge:
    map(to_entries) | add | group_by(.key) | map(
        { "key": (.[0].key)
        , "value": (
            if .[0].key == "contents"
            then [ .[].value ] | add | group_by(.name) | map(merge)
            elif [ .[].value == .[0].value ] | all
            then .[0].value
            else error("can't merge incompatible values for key '\(.[0].key)'")
            end
        ) }
    ) | from_entries
;

# Add paths to each object, that is, the names of the ancestors.
def directory:
    def f($d): .dir=($d|join("/")) | .name as $n | .contents[]?|=f($d+[$n]);
    f([])
;

# Every leaf node gets a basename, eg name without extension.
def basename:
    (entries | select(has("contents") | not)) |= (
        .basename = (.name | sub(".([A-z]*)$";""))
    )
;

# Any page gets its target formats.
def formats($all_formats):
    entries |= (
        .formats = [
            (.make // empty) |
            if . == "null" then empty else . end | # fix for wrong YAML parse
            if (. | type) == "array" then .[] else . end |
            tostring | ascii_downcase |
            if [. == $all_formats[]] | any then .
            elif . == "all" then $all_formats[]
            else error("unrecognized format: \(.)")
            end
        ]
    )
;

# Any page is linked to its first target format.
def link:
    (entries | select(.formats | at_least(1))) |= (
        .link = "\(.dir)/\(.basename).\(.formats[0])"
    )
;

# Front matter is the page to be associated with the enclosing directory rather
# than itself.
def frontmatter:
    (entries | select(has("contents"))) |= (
        (.frontmatter = [.contents[] | select(.frontmatter | bool)][0]) |
        (.contents = .contents - [.frontmatter])
    )
;

# Any page that has no link should be excluded from the index. It would be
# nicer if we could remove in one swoop with `entries | ... |= empty`. It only
# works sometimes, presumably since we'd change the objects we'd iterate over.
def clean:
    if has("contents") then .contents |= map(clean)
    elif has("link")   then .
    else empty end
;

# Add links to the next and previous page for every linked page.
def navigation:
    def f($paths; $i; $j; $key):
        setpath($paths[$i]+[$key];
            getpath($paths[$j]) | {link,title}
        )
    ;
    [ path(entries | select(.formats | at_least(1))) ] as $paths
    | ($paths | length) as $n
    | reduce range(0; $n-1) as $i (.; f($paths; $i; $i+1; "next"))
    | reduce range(1; $n)   as $i (.; f($paths; $i; $i-1; "prev"))
;

# Sort content first according to sort order in metadata.
def sorting:
    (entries | select(has("contents")) | .contents) |= (
        sort_by(.[.sortby // ""] // .sort // .title // .name)
    )
;

# Add a note that tells us whether this has only children who have no more
# subchildren.
def annotate_leaves:
    (entries | select(has("contents"))) |= (
        .only_leaves = (.contents | all(has("contents") | not))
    )
;

# Combines the given stream of JSON objects by merging them, and performs the
# given operations to turn it into a proper index.
def index($all_formats):
    merge
    | directory
    | basename
    | formats($all_formats)
    | link
    | clean
    | navigation
    | frontmatter
    | sorting
    | annotate_leaves
;

# Get target files and their dependencies as an enumeration of {"target":...,
# "dependencies":...} objects.
def targets($dest; $default_style):
    entries
    | ., (.frontmatter // empty)
    | .formats[] as $format
    | "\($dest)/\(.dir)/\(.basename).\($format)" as $doc
    | ["\($dest)/\(.dir)/\(.resources?[])"] as $external
    | ["\($dest)/\(.style // $default_style).css"] as $css
    | (if $format == "html" then ($css + $external) else [] end) as $linked
    | (if $format == "pdf"  then ($css + $external) else [] end) as $embedded
    | {"target": $format, "dependencies": ([$doc] + $linked) }
    , {"target": $doc, "dependencies": ($embedded) }
    , {"target": $doc, "dependencies": ["NEXT_LINK := \( .next.link // empty)"]}
    , {"target": $doc, "dependencies": ["PREV_LINK := \( .prev.link // empty)"]}
    , {"target": $doc, "dependencies": ["NEXT_TITLE := \( .next.title // empty)"]}
    , {"target": $doc, "dependencies": ["PREV_TITLE := \( .prev.title // empty)"]}
;

#!/usr/bin/env jq
# This is a collection of filters for `jq`, intended to manipulate JSON objects
# into JSON representing a website index, for further processing in a template.

# Convert "truthy" value to actual boolean.
def bool:
    [. == (null,false,0,{},[])] | any | not
;

# Is a given array at least length $n?
def at_least($n):
    (. | length) >= $n
;

# Generate this object and all its descendants.
def entries:
    ., recurse(.contents?[]?)
;

# Wrap an object in other objects so that the original object exists at a
# particular "path". Like `{} | setpath(["a","b"], …)`, but instead of making
# objects like `{"a":{"b":…}}`, this makes objects like `{"name":"a",
# "contents":[{"name":"b",…}]}`. We use `name` and `contents` to be compatible
# with the output of the `tree` program on the shell.
def tree($path):
    if $path | at_least(2)
    then { "contents": [ tree($path[1:]) ] }
    else .
    end | .name = $path[0]
;

# Merge an array of page objects into a single page object.
def merge:
    map(to_entries) | add | group_by(.key) | map(
        { "key": (.[0].key)
        , "value": (
            if .[0].key == "contents"
            then [ .[].value ] | add | group_by(.name) | map(merge)
            elif [ .[].value == .[0].value ] | all
            then .[0].value
            else error("can't merge incompatible values for key '\(.[0].key)'")
            end
        ) }
    ) | from_entries
;

# Add paths to each object, that is, the names of the ancestors.
def directory:
    def f($d): .dir=($d|join("/")) | .name as $n | .contents[]?|=f($d+[$n]);
    f([])
;

# Every leaf node gets a basename, eg name without extension.
def basename:
    (entries | select(has("contents") | not)) |= (
        .basename = (.name | sub(".([A-z]*)$";""))
    )
;

# Any page gets its target formats.
def formats($all_formats):
    entries |= (
        .formats = [
            (.make // empty) |
            if . == "null" then empty else . end | # fix for wrong YAML parse
            if (. | type) == "array" then .[] else . end |
            tostring | ascii_downcase |
            if [. == $all_formats[]] | any then .
            elif . == "all" then $all_formats[]
            else error("unrecognized format: \(.)")
            end
        ]
    )
;

# Any page is linked to its first target format.
def link:
    (entries | select(.formats | at_least(1))) |= (
        .link = "\(.dir)/\(.basename).\(.formats[0])"
    )
;

# Front matter is the page to be associated with the enclosing directory rather
# than itself.
def frontmatter:
    (entries | select(has("contents"))) |= (
        (.frontmatter = [.contents[] | select(.frontmatter | bool)][0]) |
        (.contents = .contents - [.frontmatter])
    )
;

# Any page that has no link should be excluded from the index. It would be
# nicer if we could remove in one swoop with `entries | ... |= empty`. It only
# works sometimes, presumably since we'd change the objects we'd iterate over.
def clean:
    if has("contents") then .contents |= map(clean)
    elif has("link")   then .
    else empty end
;

# Add links to the next and previous page for every linked page.
def navigation:
    def f($paths; $i; $j; $key):
        setpath($paths[$i]+[$key];
            getpath($paths[$j]) | {link,title}
        )
    ;
    [ path(entries | select(.formats | at_least(1))) ] as $paths
    | ($paths | length) as $n
    | reduce range(0; $n-1) as $i (.; f($paths; $i; $i+1; "next"))
    | reduce range(1; $n)   as $i (.; f($paths; $i; $i-1; "prev"))
;

# Sort content first according to sort order in metadata.
def sorting:
    (entries | select(has("contents")) | .contents) |= (
        sort_by(.sort // .title // .name)
    )
;

# Add a note that tells us whether this has only children who have no more
# subchildren.
def annotate_leaves:
    (entries | select(has("contents"))) |= (
        .only_leaves = (.contents | all(has("contents") | not))
    )
;

# Combines the given stream of JSON objects by merging them, and performs the
# given operations to turn it into a proper index.
def index($all_formats):
    merge
    | directory
    | basename
    | formats($all_formats)
    | link
    | clean
    | navigation
    | frontmatter
    | sorting
    | annotate_leaves
;

# Get target files and their dependencies as an enumeration of {"target":...,
# "dependencies":...} objects.
def targets($dest; $default_style):
    entries
    | ., (.frontmatter // empty)
    | .formats[] as $format
    | "\($dest)/\(.dir)/\(.basename).\($format)" as $doc
    | ["\($dest)/\(.dir)/\(.resources?[])"] as $external
    | ["\($dest)/\(.style // $default_style).css"] as $css
    | (if $format == "html" then ($css + $external) else [] end) as $linked
    | (if $format == "pdf"  then ($css + $external) else [] end) as $embedded
    | {"target": $format, "dependencies": ([$doc] + $linked) }
    , {"target": $doc, "dependencies": ($embedded) }
    , {"target": $doc, "dependencies": ["NEXT_LINK := \( .next.link // empty)"]}
    , {"target": $doc, "dependencies": ["PREV_LINK := \( .prev.link // empty)"]}
    , {"target": $doc, "dependencies": ["NEXT_TITLE := \( .next.title // empty)"]}
    , {"target": $doc, "dependencies": ["PREV_TITLE := \( .prev.title // empty)"]}
;


:new: throw an error if an entity id does not exist.

jsoniq version "1.0";
module namespace japan = "http://28.io/modules/xbrl/profiles/japan/core";

import module namespace mw = "http://28.io/modules/xbrl/mongo-wrapper";

import module namespace archives = "http://28.io/modules/xbrl/archives";
import module namespace entities = "http://28.io/modules/xbrl/entities";

(:
 : Copyright 2012-2015 28msec Inc.
 :)
(:~
 :
This module provides functionality for querying against the Japan profile.

 :
 : @author Ghislain Fourny
 :
 :)

(:~
 :
Retrieves the entities with the given identifiers.

 :
 : @param $cik a sequence of shortcut codes, like E01225.
 : @param $eid a sequence of raw EIDs.
 : @param $tag a sequence of tags (e.g., indices).
 :
 : @return the entities that match those identifiers.
 :)
declare function japan:entities(
    $cik as string*,
    $eid as string*,
    $tag as string*
) as object*
{
  let $eid := distinct-values((
    $cik ! ("http://info.edinet-fsa.go.jp " || $$ || "-000"),
    $eid
  ))
  return
    switch(true)
    case $tag = "ALL" return entities:entities()
    case exists(($eid, $tag)) return
       for $entity in (
         for $tag in $tag
         return mw:find($entities:col, { "Profiles.FSA.Tags" : $tag }),

         let $entities := entities:entities($eid)
         let $idsNotFound :=
           for $id in $eid
           let $entity := $entities[$$._id eq $id]
           where empty($entity)
           return $id
         return
           if(empty($idsNotFound))
           then $entities
           else error(xs:QName("japan:ENTITY_NOT_FOUND"),
                      string-join($idsNotFound ! ("'" || $$ || "'"), ",") || ": Entities not found.")
       )
       group by $entity._id
       return $entity[1]
    default return ()
};

(:~
 :
Retrieves the filings with the given characteristics.

 :
 : @param $entities a sequence of entities or EIDs.
 : @param $fiscalYear a sequence of fiscal years.
 : @param $fiscalPeriod a sequence of fiscal periods.
 : @param $aid a sequence of AIDs.
 :
 : @return the filings that match those criteria.
 :)
declare function japan:filings(
    $entities as item*,
    $fiscalYear as integer*,
    $fiscalPeriod as string*,
    $aid as string*) as object*
{
    archives:archives($aid),
    if($fiscalYear = 1)
    then
        for $a as object in archives:archives-for-entities($entities)
        where (empty($fiscalPeriod) or ($fiscalPeriod = "ALL") or $a.Profiles.FSA.DocumentFiscalPeriodFocus = $fiscalPeriod)
        group by $a.Entity
        return
            for $filing in $a
            group by $fy := $filing.Profiles.FSA.DocumentFiscalYearFocus
            order by $fy descending
            count $i where $i eq 1
            return $filing
    else
        for $a as object in archives:archives-for-entities($entities)
        where (empty($fiscalYear) or
               $fiscalYear = 0 or
               $fiscalYear = $a.Profiles.FSA.DocumentFiscalYearFocus)
               and (empty($fiscalPeriod) or ($fiscalPeriod = "ALL") or $a.Profiles.FSA.DocumentFiscalPeriodFocus = $fiscalPeriod)
        return $a
};

jsoniq version "1.0";
module namespace japan = "http://28.io/modules/xbrl/profiles/japan/core";

import module namespace mw = "http://28.io/modules/xbrl/mongo-wrapper";

import module namespace archives = "http://28.io/modules/xbrl/archives";
import module namespace entities = "http://28.io/modules/xbrl/entities";

(:
 : Copyright 2012-2015 28msec Inc.
 :)
(:~
 :
This module provides functionality for querying against the Japan profile.

 :
 : @author Ghislain Fourny
 :
 :)

(:~
 :
Retrieves the entities with the given identifiers.

 :
 : @param $cik a sequence of shortcut codes, like E01225.
 : @param $eid a sequence of raw EIDs.
 : @param $tag a sequence of tags (e.g., indices).
 :
 : @return the entities that match those identifiers.
 :)
declare function japan:entities(
    $cik as string*,
    $eid as string*,
    $tag as string*
) as object*
{
  let $eid := distinct-values((
    $cik ! ("http://info.edinet-fsa.go.jp " || $$ || "-000"),
    $eid
  ))
  return
    switch(true)
    case $tag = "ALL" return entities:entities()
    case exists(($eid, $tag)) return
       for $entity in (
         for $tag in $tag
         return mw:find($entities:col, { "Profiles.FSA.Tags" : $tag }),
         entities:entities($eid)
       )
       group by $entity._id
       return $entity[1]
    default return ()
};

(:~
 :
Retrieves the filings with the given characteristics.

 :
 : @param $entities a sequence of entities or EIDs.
 : @param $fiscalYear a sequence of fiscal years.
 : @param $fiscalPeriod a sequence of fiscal periods.
 : @param $aid a sequence of AIDs.
 :
 : @return the filings that match those criteria.
 :)
declare function japan:filings(
    $entities as item*,
    $fiscalYear as integer*,
    $fiscalPeriod as string*,
    $aid as string*) as object*
{
    archives:archives($aid),
    if($fiscalYear = 1)
    then
        for $a as object in archives:archives-for-entities($entities)
        where (empty($fiscalPeriod) or ($fiscalPeriod = "ALL") or $a.Profiles.FSA.DocumentFiscalPeriodFocus = $fiscalPeriod)
        group by $a.Entity
        return
            for $filing in $a
            group by $fy := $filing.Profiles.FSA.DocumentFiscalYearFocus
            order by $fy descending
            count $i where $i eq 1
            return $filing
    else
        for $a as object in archives:archives-for-entities($entities)
        where (empty($fiscalYear) or
               $fiscalYear = 0 or
               $fiscalYear = $a.Profiles.FSA.DocumentFiscalYearFocus)
               and (empty($fiscalPeriod) or ($fiscalPeriod = "ALL") or $a.Profiles.FSA.DocumentFiscalPeriodFocus = $fiscalPeriod)
        return $a
};


fixed precedence bug

fixed precedence bug

import module namespace report-schemas = "http://xbrl.io/modules/bizql/report-schemas";
import module namespace sec = "http://xbrl.io/modules/bizql/profiles/sec/core";
import module namespace companies = "http://xbrl.io/modules/bizql/profiles/sec/companies";
import module namespace sec-fiscal = "http://xbrl.io/modules/bizql/profiles/sec/fiscal/core";
import module namespace entities = "http://xbrl.io/modules/bizql/entities";
import module namespace archives = "http://xbrl.io/modules/bizql/archives";
import module namespace response = "http://www.28msec.com/modules/http-response";
import module namespace request = "http://www.28msec.com/modules/http-request";
import module namespace session = "http://apps.28.io/session";

variable $cik := let $cik := request:param-values("cik","0000021344")
                 return if (empty($cik))
                            then error(QName("local:INVALID-REQUEST"), "cik: mandatory parameter not found")
                            else $cik;
variable $periodFocus := let $periodFocus := request:param-values("fiscalPeriodFocus","FY")
                         return if (empty($periodFocus))
                                then error(QName("local:INVALID-REQUEST"),"fiscalPeriodFocus: mandatory parameter not found")
                                else $periodFocus;
variable $yearFocus := let $yearFocus := request:param-values("fiscalYearFocus","2011") ! ($$ cast as integer)
                       return if (empty($yearFocus))
                                then error(QName("local:INVALID-REQUEST"), "fiscalYearFocus: mandatory parameter not found")
                                else $yearFocus;

variable $entity := let $entity := entities:entities($cik ! companies:eid($$))
                    return if (empty($entity))
                           then  error(QName("local:INVALID-REQUEST"), "Given CIK:"||$cik|| " not found")
                           else  $entity;

variable $reportSchema := let $reportSchema := request:param-values("reportSchema","FundamentalAccountingConcepts")
                          return if(empty($reportSchema))
                          then error(QName("local:INVALID-REQUEST"),"reportSchema: mandatory parameter not found")
                          else $reportSchema;

variable $schema := let $schema := report-schemas:report-schemas($reportSchema)
                    return if (empty($schema))
                    then  error(QName("local:INVALID-REQUEST"), "Given reportSchema:"||$schema|| " not found")
                    else $schema;

variable $aid := request:param-values("aid");

for $archive in
        (if (exists($entity))
        then
            let $a :=
                    sec-fiscal:filings-for-entities-and-fiscal-periods-and-years($entity, $periodFocus, $yearFocus)
                return if (empty($a))
                       then  error(QName("local:INVALID-REQUEST"), "Filing not found")
                       else  (for $a in $a
                             order by $a.Profiles.SEC.AcceptanceDatetime
                             return $a)[1]
        else (), archives:archives($aid))
let $format  := lower-case(substring-after(request:path(), ".jq.")) (: text, xml, or json (default) :)
let $populatedSchema := sec:populate-schema-with-facts($schema, $archive)
return  if(session:only-dow30($entity) or session:valid())
        then [ $populatedSchema ]
        else {
            response:status-code(401);
            session:error("accessing filings of an entity that is not in the DOW30", $format)
        }

import module namespace report-schemas = "http://xbrl.io/modules/bizql/report-schemas";
import module namespace sec = "http://xbrl.io/modules/bizql/profiles/sec/core";
import module namespace companies = "http://xbrl.io/modules/bizql/profiles/sec/companies";
import module namespace sec-fiscal = "http://xbrl.io/modules/bizql/profiles/sec/fiscal/core";
import module namespace entities = "http://xbrl.io/modules/bizql/entities";
import module namespace archives = "http://xbrl.io/modules/bizql/archives";
import module namespace response = "http://www.28msec.com/modules/http-response";
import module namespace request = "http://www.28msec.com/modules/http-request";
import module namespace session = "http://apps.28.io/session";

variable $cik := let $cik := request:param-values("cik","0000021344")
                 return if (empty($cik))
                            then error(QName("local:INVALID-REQUEST"), "cik: mandatory parameter not found")
                            else $cik;
variable $periodFocus := let $periodFocus := request:param-values("fiscalPeriodFocus","FY")
                         return if (empty($periodFocus))
                                then error(QName("local:INVALID-REQUEST"),"fiscalPeriodFocus: mandatory parameter not found")
                                else $periodFocus;
variable $yearFocus := let $yearFocus := request:param-values("fiscalYearFocus","2011")
                       return if (empty($yearFocus))
                                then error(QName("local:INVALID-REQUEST"), "fiscalYearFocus: mandatory parameter not found")
                                else $yearFocus cast as integer;

variable $entity := let $entity := entities:entities($cik ! companies:eid($$))
                    return if (empty($entity))
                           then  error(QName("local:INVALID-REQUEST"), "Given CIK:"||$cik|| " not found")
                           else  $entity;

variable $reportSchema := let $reportSchema := request:param-values("reportSchema","FundamentalAccountingConcepts")
                          return if(empty($reportSchema))
                          then error(QName("local:INVALID-REQUEST"),"reportSchema: mandatory parameter not found")
                          else $reportSchema;

variable $schema := let $schema := report-schemas:report-schemas($reportSchema)
                    return if (empty($schema))
                    then  error(QName("local:INVALID-REQUEST"), "Given reportSchema:"||$schema|| " not found")
                    else $schema;

variable $aid := request:param-values("aid");

for $archive in
        (if (exists($entity))
        then
            let $a :=
                    sec-fiscal:filings-for-entities-and-fiscal-periods-and-years($entity, $periodFocus, $yearFocus)
                return if (empty($a))
                       then  error(QName("local:INVALID-REQUEST"), "Filing not found")
                       else  (for $a in $a
                             order by $a.Profiles.SEC.AcceptanceDatetime
                             return $a)[1]
        else (), archives:archives($aid))
let $format  := lower-case(substring-after(request:path(), ".jq.")) (: text, xml, or json (default) :)
let $populatedSchema := sec:populate-schema-with-facts($schema, $archive)
return  if(session:only-dow30($entity) or session:valid())
        then [ $populatedSchema ]
        else {
            response:status-code(401);
            session:error("accessing filings of an entity that is not in the DOW30", $format)
        }


:pencil: Fix reprt element test.

:pencil: Fix reprt element test.

設備休止関連損失、特別損失

設備休止関連損失、特別損失

設備休止関連損失、特別損失

設備休止関連損失、特別損失

損益計算書　財務諸表等規則様式第三号

設備休止関連損失、特別損失

設備休止関連損失、特別損失

連結損益計算書　連結財務諸表規則様式第五号

Notes regarding the loss of inactive facilities[text block]

設備休止関連損失に関する注記[テキストブロック]

設備休止関連損失に関する注記

設備休止関連損失、特別損失

設備休止関連損失、特別損失

設備休止関連損失、特別損失

設備休止関連損失、特別損失

設備休止関連損失に関する注記

設備休止関連損失に関する注記[テキストブロック]

設備休止関連損失、特別損失

設備休止関連損失、特別損失